由于公司原因,唯一会ios的伙伴要离开了,临时要接手ios的开发任务,只有30天的交接时间,记录下这个过程
一开始,给自己定的步骤是这样的
- 学习objective-c语言(书本:objective-c应用开发全程实录)
- 学习ios基础(iOS开发实战:从入门到上架App Store(第2版))
- 学习ios高级(后续阶段,不在第一阶段范围,书本:iOS开发快速进阶与实战)
- 熟悉系统框架,热门第三方库,jenkins打包,App Store,开发者账号相关,CocoaPods,调试、bugly线上问题定位
主要选择的是文字类的资料,不考虑视频,因为视频资料学习起来多花时间,不适合,目的是为了快速接手工作,学习的重点如下: 学习OC、学习UI绘制、学习各种事件响应,学习数据加载和传递、学习动态自适应UI
objective-c的学习
ios开发最新的书籍都是6年前的了,最近几年都没有入门的ios开发的书籍出来,看来最新学ios的人太少了吧
oc的学习过程没什么问题,大概耗费5天的时间,看完了objective-c应用开发全程实录这本书,oc的数据类型和语法跟Android,JS都不一样,要重新了解,这里面比较坑的是IB的界面开发,学习了一半半,进度缓慢,一个是最新的Xcode界面跟书本的有差距,另外是学着有点怀疑这个不好满足实际业务开发,后来经过了解,实际项目中,已经不用IB界面开发了,都是手写布局,遂放弃,还好及时止损,没有占用太多精力在上面
这本书跟ios开发基础这本书内容有诸多重叠,故直接跳过这个步骤了,加快进度
ios开发基础
首先是熟悉Xcode这个IDE,然后直接基于现有项目的一个简单的页面,自己手动实现一遍,我挑选的是设置页,不涉及网络请求,只是布局的展示,花了三天的时间(本职工作外的时间),把这个页面自己手动写出来;对照着官方的组件文档,熟悉界面布局的方法和功能
这个设置页,使用了UITableView,要熟悉这个view匹配的UITableViewDataSource这个delegate的11个回调方法,和UITableViewDelegate的十几个回调方法;还有熟悉字体,颜色大小等各种布局的写法,刚开始写还是有点吃力
上手过程中,很不习惯的还有IDE,要重新熟悉Xcode的快捷键,还有很多功能,其他IDE有提供,但是Xcode上没有,只能手动写
同样的数据跟UI绑定,ios上实现会比Android复杂不少,需要实现的回调也会多不少,不过效果上ios更强大,可以实现更多的功能;不过都统统被H5的Vue吊打,各种前端对比后,Vue是最方便简单的
现有项目的熟悉
对于现有项目熟悉,列取了一个清单如下
- 手写UI布局,了解了字体字号,自适应的布局,常见的UI组件的使用,富文本,事件响应,布局层级,渐变这些场景
- 基于网络请求的复杂列表的布局动态实现,数据模型配置
- 熟悉页面跳转,传参,路由配置
- 项目的整体架构设计,全局扩展方法配置
- 了解项目网络架构设计
- 数据存储,全局token,登入状态,userCode的动态监听,token失效如何触发所有页面的刷新机制
- 崩溃的定位(本地崩溃,线上崩溃)
- 断点调试(条件断点,全局断点,调用断点)
- Jenkins打包的配置,开发账号续费,证书维护,TestFlight发布,审核上线
- touch事件在不同层级view的传递和拦截机制,手势处理,可以处理复杂UI交互
- 多线程的处理
- 多媒体,权限,相册的处理
- 性能优化,内存泄露的排查,卡顿跟耗时方法的定位
- ios推送机制的了解
- 了解项目依赖的第三方的库的场景和使用
熟悉方式主要就是看现有项目的代码,不懂的就配合官方文档查看,或者Google搜索,问交接的同事等
这个清单,优先级最高的,是跟UI布局,网络和Jenkins打包相关的,这部分先熟悉上手,考虑到时间因素,上面列取的点只有60%先做了了解,其他的只能放后面待有空了,再来补上
实际需求上手
光熟悉代码还远远不够,还是要自己独立完成需求开发,刚好目前手上有两个ios的开发需求,于是就拿来练手
实际写代码,一开始最难的是不熟练,对OC语言的不熟练,对ios组件的不熟练,对项目封装的全局方法的使用不熟练;这个时候,最好的办法,就是参考其他页面类似的功能,看它是怎么写的,再照搬做下修改调整,相对于自己从零开始写,会快很多;写到后续稍微熟练后,同个功能,ios的实现耗时大概是Android的两倍,如果是一个全新的功能,没有其他页面可以参考的话,耗时还会更大的增加
另外实际开发中,对于实现效果也会有一些妥协,比如首页的资质证明功能,是上下两个UI,我采用的是写死布局位置的方法,当一个不可见,另外一个更新新的布局位置,而不适用动态的约束布局,自动适应(对这个布局写法不熟悉),时间赶,所以先妥协的实现了;这种类似妥协的地方也会有一些,只能待后续慢慢优化
后续遗漏的问题
一个就是对现有的项目的代码框架做进一步的熟悉,熟悉各种全局的拓展和宏定义,熟悉masonry框架,对各种UI布局可以快速的实现;熟悉各种性能场景,以及内存泄露场景,目的是写出高质量的代码
ios开发不一样的地方
上手ios开发,会碰到跟其他前端语言很不一样的地方,选几个列取下
方法的调用,需要加中括号
代码语言:javascript复制[UILabel alloc]
上面的代码,代表执行UILabel类的alloc方法
对变量的声明,需要指定属性特性
代码语言:javascript复制@property(copy, nonatomic) NSString *name;
代表name的变量,是用复制值的方式setter的,并且不保证线程安全 类型有:assign、atomic、copy、retain、strong、week
每个类都要有.m和.h两个文件,比如page.h和page.m,.h是做声明的,对外部其他类可见,包括变量和方法,.m是具体实现方法的,也包括定义内部变量和方法
控件宽高在布局代码写完后,居然可以直接拿到
代码语言:javascript复制UILabel *tempLabel = [[UILabel alloc] initWithFrame:CGRectZero];
tempLabel.text = @"asfasfsdafsda";
[tempLabel sizeToFit];
NSLog(@"weigan width %f", tempLabel.width);
YGP[11167:4125186] weigan width 106.000000
报错的代码是定位到指针,比较难直接通过报错的log来定位问题
代码语言:javascript复制023-08-24 11:20:54.219074 0800 YGP[26626:4249029] -[NSNull isEqualToString:]: unrecognized selector sent to instance 0x7ff865b1f580
2023-08-24 11:20:54.261052 0800 YGP[26626:4249029] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull isEqualToString:]: unrecognized selector sent to instance 0x7ff865b1f580'
*** First throw call stack:
(
0 CoreFoundation 0x00007ff8004288ab __exceptionPreprocess 242
1 libobjc.A.dylib 0x00007ff80004dba3 objc_exception_throw 48
2 CoreFoundation 0x00007ff800437ab8 [NSObject(NSObject) instanceMethodSignatureForSelector:] 0
3 CoreFoundation 0x00007ff80042cd71 ___forwarding___ 1431
4 CoreFoundation 0x00007ff80042f068 _CF_forwarding_prep_0 120
5 YGP 0x000000010ffbb1f8 __38-[YGPCOMMUniverCellModel isBaiyiButie]_block_invoke 136
6 CoreFoundation 0x00007ff80038b4bc __NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ 7
7 CoreFoundation 0x00007ff80044a471 -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] 179
8 YGP 0x000000010ffbb0ff -[YGPCOMMUniverCellModel isBaiyiButie] 223
9 YGP 0x0000000110177b8f -[YGPCOMMUniversalCell layoutCellAndComputeHeight:] 223
10 YGP 0x000000010fe60c5c -[YGPCOMMSearchCell layoutCellAndComputeHeight:] 92
11 YGP 0x000000010ff77a20 [YGPSearchCOMMCellLayoutHelper cellHeightWithModel:] 144
12 YGP 0x00000001101415e3 -[YGPCOMMSearchCellModel setCellType:] 83
13 YGP 0x000000011014cb3a __73-[YGPCOMMSearchListVC dealCOMMUnivesalDataWith:tagItemHeight:layoutType:]_block_invoke 490
14 CoreFoundation 0x00007ff80038b4bc __NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ 7
15 CoreFoundation 0x00007ff800475fbf -[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:] 80
16 YGP 0x000000011014c88e -[YGPCOMMSearchListVC dealCOMMUnivesalDataWith:tagItemHeight:layoutType:] 1134
17 YGP 0x000000011014cd9a -[YGPCOMMSearchListVC dealSearchProdAndRecommendData:complete:] 522
18 YGP 0x000000011014c0d6 __64-[YGPCOMMSearchListVC configSearchProdWithModel:recommendArray:]_block_invoke.185 742
19 YGP 0x000000011008e62c -[YGPNetworkRequest requestCompleteAndHandleResult:error:complete:] 7324
20 YGP 0x000000011008bf93 __100-[YGPNetworkRequest dataTaskWithHTTPMethod:URLString:parameters:headerParameters:progress:complete:]_block_invoke_2 179
21 YGP 0x000000011035b405 __124-[AFHTTPSessionManager dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:]_block_invoke_2 197
22 YGP 0x000000011037847d __72-[AFURLSessionManagerTaskDelegate URLSession:task:didCompleteWithError:]_block_invoke_2.108 189
23 libdispatch.dylib 0x0000000111a80d18 _dispatch_call_block_and_release 12
24 libdispatch.dylib 0x0000000111a81f5b _dispatch_client_callout 8
25 libdispatch.dylib 0x0000000111a92e5c _dispatch_main_queue_drain 1726
26 libdispatch.dylib 0x0000000111a92790 _dispatch_main_queue_callback_4CF 31
27 CoreFoundation 0x00007ff800387b1f __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ 9
28 CoreFoundation 0x00007ff800382436 __CFRunLoopRun 2482
29 CoreFoundation 0x00007ff8003816a7 CFRunLoopRunSpecific 560
30 GraphicsServices 0x00007ff809cb128a GSEventRunModal 139
31 UIKitCore 0x00000001213b6ad3 -[UIApplication _run] 994
32 UIKitCore 0x00000001213bb9ef UIApplicationMain 123
33 YGP 0x000000010fe31a88 main 104
34 dyld 0x00000001117762bf start_sim 10
35 ??? 0x00000001204c252e 0x0 4836828462
)
一个有点不好看懂的代码(外面的中括号不能拿掉)
代码语言:javascript复制@property (nonatomic, assign) NSInteger timeInterval;
self.timeInterval = [endDate ? endDate : [NSDate date] timeIntervalSinceDate:[NSDate date]];
block内部有引用self的话,需要带声明,不然会引起泄露(没写也没告警)
代码语言:javascript复制 @weakify(self);
[self postListByTypeWithCompletionHandler:^(NSError * _Nullable error, id _Nullable dataObject) {
@strongify(self);
HideHUD(self.view);
self.tableView.mj_footer.hidden = NO;
[self resetNoDataView];
if (!error && dataObject) {
[self dealSearchCOMMDatas:dataObject];
} else {
if (self.dataArrays.count == 0) {
[self loadNoDataView];
}
}
complete();
}];