内容源自视频内容摘取和总结:
https://www.bilibili.com/video/av49317023
1、OC语言的跑偏
1、如何掌握高级编程语言:
对于Oc来说,底层思维是基础,大型复杂项目需要用到面向对象思维。
底层思维 | 抽象思维 |
---|---|
向下,如何把握机器底层从微观理解对象构造 | 向上,如何将我们的周围世界抽象为程序代码 |
语言构造 编译转换 内存模型 运行时机制 |
面向对象 组件封装 设计模型 构架模式 |
2、“时空人”三位一体分析法
-
对时间分析——发生在什么时候?
- compile-time VS run-time
-
空间分析——变量放在那里?
- stack VS heap
-
人物分析——代码那里来的?
- progranmmer VS compler/runtime/framework
Hello World
//引入头文件,头文件.h,实现文件为.m
#import <Foundation/Faundation.h>
//函数入口点
int main(int argc, const char * argv[]){
//为了支持ARC的pool
@autoreleasepool{
//@是Oc的字符串
Nslog(@"Hello,World!")
}
return 0;
}
2、iOS的跑偏
2.1、App基本概念
2.1.1iOS App的代码结构
- main()
- UIapplicationMain():
- main()函数中调用
- 主要工作:①生成一个UIApplication对象;② 将UIApplicationDelegate返回给?
- UIApplication对象
- UIApplicationDelegate (我们的主要工作是管理这个)
- iOS App的运行环境
- Sandbox
- 运行期目录结构
- NSHomeDirectory()
2.1.2Bundle
- IOS应用是一个Bundle
- bundle:带有Info.plist的目录
- NSBundle类
- mainBundle
- resource bundle 和 framework
2、基础理论支持
2.1.1界面和代码要分离
- 可以只用代码来秒回界面及影响用户操作
- 但是
- 不直观
- 调整麻烦
- iOS的解决方案:
-
用Interface Builder 画界面——保存到xib(xml版的nib文件)
> nib:NEXTSTEP InterfaceBuilder -
用代码更新界面、影响用户的操作——保存到.m文件里
-
- 两个小麻烦
- 界面操作怎么制定相应代码
- 代码怎么引用界面元素
- Outlet
- 为了让代码能引用nib中的对象
- 需要代码里有一个变量来引用界面对象
- 在界面对象创建后,给这个变量赋值
- 这个过程最好能自动完成
- Outlet
- IBoutlet标记的变量
- Connection
-Outlet Connection
<connection>
//变量名:property="messageLabel"
//引用的界面模板元素id:destination="Sik-hr-KEe"
<outlet property="messageLabel" destination="Sik-hr-KEe" id="qCb-1M-csN" />
<outlet property="nameField" destination="x9C-NC-3Hg" id="L1H-Uq-oGn" />
</ connections>
- 存在xib里的是界面模板
- 运行时,类实例的代码会出发界面实例化
- 最终调用[UINib instantitateWithOwner:options];
- 细节会在View Controler 部分讲解
- 根据模板实例化其中的对象([UINib instantitateWithOwner:options])
- [owner -setValue: uiObj forKey:outlet.property]—— 按照模板id??
- Action Connection
-(IBAction)greeting:(id)sender{
//...
}
2.2 UIButton
Demo
输入名字点击按钮后出现打招呼信息
control+拖动控件到文件中实现了两个步骤:
1. 创建一个IBAction的方法
2. 方法和按钮的关联关系建立起来
-(IBAction)greeting:(id)sender{
//get user name
//compose message
//show message
}
TextFaild声明:
- 1. 删除声明代码时,要把界面上的connection删除,不然会造成crash
- 2. 最好不要再头文件中书写,这样会暴露给外部(除非有暴露的需要)
@interface GameViewController ()
@property (weak, nonatomic) IBOutlet UITextField *nameField;
@end
代码充实:
-(IBAction)greeting:(id)sender{
//get user name
NSString * name = @"";
name = self.nameField.text;
//compose message
NSString * message =@"";
message = [NSString stringWithFormat: @"你好!%@!",name];
//show message
self.helloMessageShow.text = message;
}
作业遗留:
-
- 解决警告(如果没有输入值时怎么办)
-
- 尝试所有属性看看是做什么的
UIbutton样式
- 类型:Custom(可以自己定义图标样式)、System(系统)
- 状态:Normal、Highlighted、Selected、Disabled
- 文字与图片
- 背景
- 代码创建 UIButton
- 创建
//buttonWithType可以保证不错漏一些信息
UIbutton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
- 定制
[btn setBackgroundImage:[UIImage imageNamed:@"okBtn"]forState:UIControlStateNormal];
[btn setTitle:@"OK" forState: UIControlStateNormal];
[btn setTitleColor:[UIColor redColor forState:UIControlStateNormal]];
- 添加响应
//action:@selector(greeting:) 一个方法的原型
//forControlEvents:UIControlEventTouchUpInside] 具体事件
[btn addTarget:self action:@selector(greeting:) forControlEvents:UIControlEventTouchUpInside];
2.3 Image
Domo
- 在Xcode里管理Asset Catalog
- 添加图片
- 资源属性
- 图片切片
- UIImage View
- 属性
- View-Mode:缩放
- state
- 指定 Alpha:影响性能
- 添加方式:
- 在IB里选图片:直接拖动添加(指定名字加载)
- 图片打包在mainBundle里
- 系统自动缓存:会一直占用缓存无法清除
- 属性
- 在Assets.xcassets中设置图片
- 图标设置
- 图片设置(怎样适配不同设备)
- 矢量图片(使用矢量图片,也要标记为矢量图片添加,并Universal)
- slicing:指定位置不随放大缩小而变化
- UIImage对象
- 加载App bundle里的图片
image = [UIImage imageName:@"mypic"];//1
image = [UIImage imageName:@"mypic" inBundle:nil compatibleWithTraitCollection:nil];//2
NSURL * url = [[NSBundle mainBundle] URLForResource:@"mypic" withEntension:@"png"];
UIImage * image = [UIImage imageWithContentsOffile:url path];//3
- 加载文件里的图片
UIIMage * image = [UIImage imageWithContentsOfFile:path];//2
UIImage * image = [UIImage imageWithData:date];//2
图片动画
- 使用关键帧矢量图片
- 建立outlet
- (voic)viewOldLoad{
[super viewOldLoad];
//Do any additional setup after loading the view, typically from a nib.
UIImage * animatedImage = [UIImage @"dongtu" duration:1.0];//1秒
self.animatedImageViewl.image = animatedImage;
}
矢量图片
- PDF格式的矢量图
- llustrator或Inkscape导出PDF
- 用Keynote也可以
- @1x 尺寸
- 在Assert Catalog里设置
2.2、第一个App
2.2.1 小游戏
需求:
1、显示图片
2、输入城市名字
3、猜对对得分,进入下一题
4、猜错不得分,进入下一题
2.2.1.1需求分析、设计
需求:
1、显示图片(展示图片的顺序没有说明,图片来源没说明)
2、输入城市名字(名字格式要求),
3、猜对对得分,进入下一题(多少分)
4、猜错不得分,进入下一题(猜错可以再尝试吗?)
5、一共几道题
设计需要划分几个大的模块
2.2.1.2 程序设计
- 静态结构+消息互动
城市数据管理
- 加载:
- 城市硬编码成数组
- 图片文件名:city+城市编号
- 图片读取历程
- 随机挑选:随机数生成
- 加载:
游戏会话管理
- 如何决定复杂度
2.2.1.3 示例代码的结构
- 说明:
-
- 尽可能使用面向对象的思想,封装出最小的接口,隐藏最多的内部细节,同时操持良好的代码合作性的一套思路下
-
- UI是我们看得见的地方
-
- ViewController是termlit??生成给你的,它负责承上启下,把内部的状态展示在界面上,把界面上的动作清理成一条消息发给我们的程序主体部分(Game对象)
-
- ViewController与Game的消息来往
- 4.1. ViewController找Game要城市的图片,要当前的进展,游戏有没有结束,把用户提供的名字发给游戏猜的方法
- 4.2 所有的核心逻辑都在Game这个类里面
-
- Game
- 5.1 CityDB:
- GameLevel 游戏关卡,每个城市封装成一个关卡,对应城市对象
- 每个城市ID封装成CityDB这个对象,使用时在内存中加载
- CityDB对象实际上只保留了一组City对象的引用,实际上是没有图片的,只有City的ID和名字
- 图片文件放在UIImage里面,每个文件以“city{id}.jpg”的方式命名
- CityDBload的时候,给了Game一个City的数组
- 当Game找CityDB要图片时,它把id拿出来拼成cityid.jpg,然后用UIImage从文件里把它load出来的
- 5.2 游戏本身的主体逻辑是什么?(初始化和准备工作)
- 初始化最关键的部分是ShuffleCities,CityDB提供的数组每次都是一样的,Game里面在初始化的时候需要“洗牌”,每个城市创建出一个GameLevel出来,不再是City加载出来的顺序了。
- 当用户的动作通过ViewController以一个猜+名字的参数消息发给Game的时候,Game的GameWithName方法就开始做工作了:
- 首先去比较一下猜对了没有,根据结果调用updateScore方法,去更新他的成绩。这样成绩计算是个独立的函数,将来可以很方便的去调整
- updateLevel:
- 把用户的一次猜测,封装成一个对象注册到GameLevel中判断一下,现在这个GameLevel里面的Guess次数是不是够多,够多的话就失败进入下一关;已经猜对了直接进入下一关
- nextLevel:在Game关卡切换里面还包含了游戏有没有玩到最后一关的判断逻辑
2.2.1.4 Domo
- 在Xocde里写出来
- 画界面
- 编写基础类
- 编写主程序
2.2.2 扫雷简单版(课外自己练习)
需求
游戏区包括雷区、地雷计数器(位于左上角,记录剩余地雷数)和计时器(位于右上角,记录游戏时间),确定大小的矩形雷区中随机布置一定数量的地雷(初级为99个方块10个雷,中级为1616个方块40个雷,高级为1630个方块99个雷,自定义级别可以自己设定雷区大小和雷数,但是雷区大小不能超过2430),玩家需要尽快找出雷区中的所有不是地雷的方块,而不许踩到地雷。
需求分析与整理
1、雷区
大小:16*16的方块
方格状态:初始、打开(1-8、空)、引爆、胜利
雷区状态:剩余未打开数量为40时,胜利
2、计时器
程序设计
- 雷区数据处理
- 加载:
- 雷区按钮数组
- 雷、数字、空白的逻辑关系
- 按钮展开与未展开状态
- 随机生成类
- 加载:
- 界面交互处理
LeiArray–>LeiButton
GameLevel–>|列表大小|LeiArray
LeiButton–>UIButton
PushBox–>|改变状态|UIButton
InnerValue–>1-8/0/9
- 说明:
-
- ViewController与Game的消息来往
- . ViewController找Game雷区按钮(状态与数字),要当前的进展,要当前时间,游戏有没有结束,把用户提供重新开始、推格子信息发给Game
- 所有的核心逻辑都在Game这个类里面
-
- Game
- 5.1 LeiArray:
- GameLevel 游戏级别,分为初级、中级、高级、自选,将级别信息提供给LeiArray,决定列表大小、雷的数量
- 每个UIBotton的展示数字、状态,封装到LeiButton中
- CityDB对象实际上只保留了一组UIButton对象的样式状态,
- 按钮存放UIButton里面,每个button有0-9,open/close来两个维度
- LeiArray load的时候,给了Game一个LeiButton数组
- 当Game找LeiButton要按钮展示时,它把每个按钮状态拿出来,拼成二位UIButton数组,然后UIButton根据状态和数字,展示对应的按钮
- 5.2 游戏本身的主体逻辑是什么?(初始化和准备工作)
- 初始化最关键的部分是ShuffleLei,LeiArray提供的数组每次都是一样的,Game里面在初始化的时候需要“洗牌”,每个UIButton创建出一个数字出来,不再是City加载出来的顺序了。
- 当用户的动作通过ViewController以一个猜+名字的参数消息发给Game的时候,Game的GameWithName方法就开始做工作了:
- 首先去比较一下猜对了没有,根据结果调用updateScore方法,去更新他的成绩。这样成绩计算是个独立的函数,将来可以很方便的去调整
- updateLevel:
- 把用户的一次猜测,封装成一个对象注册到GameLevel中判断一下,现在这个GameLevel里面的Guess次数是不是够多,够多的话就失败进入下一关;已经猜对了直接进入下一关
- nextLevel:在Game关卡切换里面还包含了游戏有没有玩到最后一关的判断逻辑
(未完成)
3、storyBoard的跑偏
-
自动创建的SingleViewApp,就已经将Main.storyboard和ViewController
- ViewController就相当于C语言中的main函数:应用程序的主入口。但是这个入口可以改
- storyboard从字面意思上理解就是故事板
- 与storyboard功能类似的还有Xib
-
storyboard
- 可以直接将控件拖入(画一些情节),转化到应用程序上就是一个个的控件
- 比较适合偏重于快速搭建复杂的静态页面 ,xib较为轻量级
-
将两个页面链接起来
- 新建A页面,在页面添加按钮,添加事件:
//我这里给按钮添加outlet的时候,事件是空心的??而且因为命名原因?已经关联到storyboard中的exit,无法使用这个方法,先忽略 - [IBAction]closeButton:(id)sender{ [self dismissViewControllerAnimated:YES completion:^()]; }
- 在mainViewController中添加进入A页面的按钮
//在ViewController.m文件中添加 #import "StartViewController.h" - (IBAction)enterBtn:(id)sender{ //如果还是以对象的创建方式new一个或alot一个init的话,拿不到testStoryboard下面的东西 //拿到刚才创建的testStoryboard UIStoryboard * newS = [UIStoryboard storyboardWithName:@"StartStoryboard" bundle:nil]; //通过storyboard创建出与他关联的那个viewController StartViewController *vc = [newS instantiateViewControllerWithIdentifier:@"StartViewController"]; //以模态视图的方式创建出来 [self presentViewController:vc animated:YES completion:^{}]; }
-
debug发生崩溃,找到有用信息,确认是名字写错了= =
‘NSInvalidArgumentException’, reason: 'Could not find a storyboard named ‘StartStoryboard’ in bundle NSBundle
-
有发生崩溃:New File的时候没有选UIController的原因,所以.m文件没有按照UIViewController模式创建
‘NSInvalidArgumentException’, reason: ‘Storyboard (<UIStoryboard: 0x28035b1c0>) doesn’t contain a view controller with identifier ‘StartStoryboard’’
- 有发生崩溃,StartStoryboard添加identity-StoryboardID也不行,可能是版本问题,勾选UseStorybored ID后,终于解决了
‘NSInvalidArgumentException’, reason: ‘Storyboard (<UIStoryboard: 0x28035b1c0>) doesn’t contain a view controller with identifier ‘TestViewController’’
-
在一个Storyboard中放更多的ViewController:
- 与上面一样,新创建的ViewController就需要新建一个.m&.h文件与他关联
- 在同一个Storyvoard中,按住Control可以将A视图拖动到B视图,(因为没有加导航控制器)只能以模态的方式去把从A视图把B视图中展示出来
-
延伸:页面dissmiss
3、计时器的跑偏
1. 获取当前时间
+(NSString*)getCurrentTimes{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
//现在时间,你可以输出来看下是什么格式
NSDate *datenow = [NSDate date];
//----------将nsdate按formatter格式转成nsstring
NSString *currentTimeString = [formatter stringFromDate:datenow];
NSLog(@"currentTimeString = %@",currentTimeString);
return currentTimeString;
}
- (因为不懂代码所以还没验证,只是按时间总结):
- 封装的内部类写在@implementation之中,同时将名字添加到@interface中声明
本节跑偏总结/复习思路:
1.创建工程:一般工程都用SingleView Application,其他类型都是自带模板的
2. 页面上的UI控件,需要outlet创建变量并建立关联后使用
3. UIButton、TextFail、UIImage控件的入门使用
4.写一个APP(一个功能)的开发流程
4. storyBoard和ViewController之间的关系,简单应用
还没整理的链接记录:
自动化框架总结
2020年Top API测试工具
阿里-性能测试技术指南
阿里-Python脚本测试
基于 Jenkins 的 CI/CD(二)
Xcode快捷键
Xcode自带iOS测试方法
xcode构建webdriverAgent时报错Messaging unqualified id的解决办法
Xcode创建终端命令
iOS------获取当前时间和当前时间戳
iOS 中的几种常用定时器
经典的测试开发面试题
SwiftUI构建完整应用
入门
三种收起键盘的方法
收起键盘2