iOS - 基础笔记
总结一些平常需要注意的点:
一、基础组件
二、组件操作
三、布局
四、基础模式
五、网络
六、线程
七、数据存储
八、多媒体
九、生命周期
十、 适配
十一、APPs
十二、组件化
十三、集成打包:
一、基础组件:
1、Frame:
frame重新赋值后会自动调节位置。
2、UILabel
-
sizeFit
方法:当UILabel设定宽高后,调用sizeFit可以自动调节宽高。 - 编辑用
UITextField
,设置内边距:
UITextField.leftViewMode = UITextFieldViewModeAlways;
UITextField.leftView = leftview;
- 多行编辑用
UITextView
,边距设置用textContainerInset
属性
3、UITableView(UITableViewDelegate,UITableViewDataSource)
- dataSource + delegate 实现数据和显示
- UITableViewCell 不一定要用xib实现,继承 UITableViewCell 就可以实现
- UITableViewCell的复用
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
}
dequeueReusableCellWithIdentifier
是根据cellId从复用队列获取。
4、UIScrollView
- 多页面的滑动不一定要用tabbar+ViewController ,可以使用UIScrollView来回切换页面。
contentSize
: 全页面的size
frame
: 屏幕内显示的size
contentOffset
: 页面坐标与屏幕坐标的差值,可以用来移动UIScrollView
5、UIImageView
contentMode
使用
6、UIButton
-
继承
UIControll
-
Target-Action
模式可以实现点击,addTarget
,不足是不能传值
7、UIView
普通view使用 UITapGestureRegconizer
+addGestureRegconizer
方法实现点击事件。
注意:addGestureRegconizer可能无效,因为手势是从上往下传递的,需要把View的userInteractionEnabled设为YES。
二、组件操作:
1、坐标转换
把局部坐标转换成全局坐标
CGRect rect = [superView convertRect:subview.frame toview:nil];
//rect是相对于someView的,以toView为坐标系重新计算rect的值
CGRect newRect = [someView convertRect:rect toView:toView];
三、布局:
1、布局的实现
- 代码
- 视图拖拽(StoryBoard)
2、代码
- Frame
主要是固定的相对布局,优点是简单的页面使用Frame
实现的效率高,缺点是复杂的组件间约束无法实现,屏幕适配也相当繁琐。 - AutoLayout
支持约束布局,通过NSLayoutConstraint
来实现,用VFL(Visual Format Lauguage)可以简化代码,第三方库Masonry
可以让实现更加简单整洁。
NSLayoutConstraint
的实现:
[NSLayoutConstraint activateConstraints:@[
[NSLayoutConstraint constraintWithItem:_avatorImageView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0],
[NSLayoutConstraint constraintWithItem:_avatorImageView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1
constant:15]
]];
注意:为什么 translatesAutoresizingMaskIntoConstraints 使用约束布局时候,就要设置为 NO?
translatesAutoresizingMaskIntoConstraints 的本意是将frame 布局
自动转化为 约束布局
,转化的结果是为这个视图自动添加所有需要的约束,如果我们这时给视图添加自己创建的约束就一定会约束冲突。
为了避免上面说的约束冲突,我们在代码创建 约束布局
的控件时 直接指定这个视图不能用frame 布局(即translatesAutoresizingMaskIntoConstraints=NO),可以放心的去使用约束了。
Reference: translatesAutoresizingMaskIntoConstraints 详解
VFL
的实现:
NSString *vflString = @"H:|-15-[_avatorImageView]-0-[_nickLabel]-(>=0)-
[_commentImageView(==_avatorImageView)]-0-[_commentLabel]-15-
[_likeImageView(==_avatorImageView)]-0-[_likeLabel]-15-
[_shareImageView(==_avatorImageView)]-0-[_shareLabel]-15-|";
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vflString
options:NSLayoutFormatAlignAllCenterY metrics:nil
views:NSDictionaryOfVariableBindings(_avatorImageView, _nickLabel,
_commentImageView, _commentLabel, _likeImageView,
_likeLabel, _shareImageView, _shareLabel)]];}
@end
Masonry
的实现:
[_hintL mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.appsIcon.mas_right);
make.centerY.mas_equalTo(self.appsIcon.mas_top);
make.width.and.height.mas_equalTo(17);
}];
四、基础模式:
类与类之间的通信1、KVO(NSKeyValueObserving)
可以监听任何object
系统提供KVO的问题:
- 移除观察者比较繁琐,容易发生Crash
- key命名问题,同名导致问题
- 实现繁琐,没能直接通过block实现
尝试KVOController
2、delegate @protocol
@protocol xxxx_Delegate <NSObject>
-(void) method:(Object *)pram;
@end
@property (nonatomic, weak) id<xxxx_Delegate> delegate;
- 多尝试
delegate(protocol)
的使用 - 与
block
的区别就是protocol
可以把不同类型的方法分组收拢,并且可以要求强制实现,实现的方式也不同,delegate
的实现可以拆分成宿主Object
的方法。 -
delegate
的调用不仅仅是判断delegate
,还要判断方法的实现与否
if(self.delegate && self.delegate responsToSelector(method:))
五、网络:
1、基本网络请求
- NSURL
[NSURL URLWithString:@"xxx"] ; //url = @"xxx"
[NSURL fileURLWithPath:@"xxx"] ;//url = @"file://xxx"
- NSURLRequest
- NSURLSession
- NSURLSessionTask
resume
/cancel
六、线程
1、NSThread
2、GCD
Grand Central Dispatch
- 线程池模式,⾃动分配/调度线程,管理线程的⽣命周期
-
对开发者使⽤队列代替线程的创建 ( 加⼊到合适的线程 ——> 加⼊到合适的队列 )
Grand Central Dispatch
分为三大类:
- 主线程对应主队列
- ⾮主线程按照优先级分为4个队列(High / Default / Low / Background)
-
⾃定义队列(DISPATCH_QUEUE_SERIAL、DISPATCH_QUEUE_CONCURRENT)
线程三大类
切换线程:
切换线程
例如:切换到主线程
dispatch_sync(dispatch_get_main_queue(), ^{
});
3、NSOperation
、NSOperationQueue
4、Runloop
总结:
iOS中的多线程基础七、数据存储:
1、key-value (NSUserDefault)
- 单例,存取轻量级的数据
- ⼀般⽤于⽤户的偏好设置
- 升级安装后还可以继续使⽤
- ⽂件存储在在 /Library/Preferences 下
2、文件
NSPathUtilities
文件工具FrameWork
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)
找置顶沙盒文件夹路径
NSFileManager
iOS⽂件管理类
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [pathArray firstObject];
NSFileManager *fileManager = [NSFileManager defaultManager];
//创建文件夹
NSString *dataPath = [cachePath stringByAppendingPathComponent:@"GTData"];
NSError *creatError;
[fileManager createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:&creatError];
//创建文件
NSString *listDataPath = [dataPath stringByAppendingPathComponent:@"list"];
[fileManager createFileAtPath:listDataPath contents:nil attributes:nil];
//查询文件
BOOL fileExist = [fileManager fileExistsAtPath:listDataPath];
//删除
if(fileExist){
[fileManager removeItemAtPath:listDataPath error:nil];
}
NSFileHandle
更精细操作的NSFileManager
特别是seekToFileOffset方法
NSFileHandle *fileHandler = [NSFileHandle fileHandleForUpdatingAtPath:listDataPath];
[fileHandler seekToEndOfFile];
[fileHandler writeData:[@"def" dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandler synchronizeFile];
[fileHandler closeFile];
3、数据库
4、序列化 NSCoder NSCoding
NSCoder
:抽象类, Object 和 ⼆进制数据间进⾏转换
NSKeyedArchiver
: NSCoder
的⼦类
NSCoding
: 对于 Object 的序列号 & 反序列化协议
NSSecureCoding
: 安全的NSCoding
NSData *listData = [NSKeyedArchiver archivedDataWithRootObject:array requiringSecureCoding:YES error:nil];
id unarchiveObj = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithObjects:[NSArray class],[GTListItem class], nil] fromData:testListdata error:nil];
<NSSecureCoding>
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
self.category = [aDecoder decodeObjectForKey:@"xxx"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.category forKey:@"xxx"];
}
+ (BOOL)supportsSecureCoding{
return YES;
}
八、多媒体
1、图片
SDWebImage
2、视频
基础使用:
AVAsset
-> AVPlayItem
-> AVPlayer
-> AVPlayerLayer
NSURL *videoURL = [NSURL URLWithString:videoUrl];
AVAsset *asset = [AVAsset assetWithURL:videoURL];
AVPlayerItem *videoItem = [AVPlayerItem playerItemWithAsset:asset];
AVPlayer *avPlayer = [AVPlayer playerWithPlayerItem:videoItem];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
playerLayer.frame = rootView.bounds
[rootView.layer addSublayer:playerLayer];
系统提供的api主要是处理播放和ui:
视频开发过程
九、生命周期
App启动过程1、main 函数
-
main 函数前
动态链接 / ⼆进制⽂件加载 / runtime / 类的加载等等 -
main 函数
职责是创建UIApplication 和 UIApplicationDelegate
main函数的实现
2、UIApplication
主要职责是:
- 处理 App ⽣命周期 / 系统内存警告
- 处理UI / statusbar / 图标消息数等状态的变化/ ⽅向
- 处理 openURL
提供 Delegate / Notification 两种⽅式处理业务逻辑:AppDelegate
控制App生命周期来调整业务逻辑:
- Not running
- Inactive:过渡的中间状态
- Active:正在前台运⾏,系统分配更多资源
- Background :分配较少资源
- Suspended: 内存不⾜系统⾃动 kill
3、UIApplicationDelegate
AppDelegate生命周期回调4、闪屏的实现
分为:Launch Screen
+Splash Screen
Launch Screen 启动屏 (系统级):
- 是Main 函数之前 + didFinshLaunch 前
- 系统启动 App 时⾃动展示
- 在准备好App UI 数据后⾃动消失(didFinshLaunch执行完之后)
- 给⽤户以响应,确定点击了正确的图标
Splash Screen 闪屏(业务逻辑)
- Launch Screen展示时间短,不能看清
- 实现同样的图⽚,显示图标等信息
- 实现⼴告 / 推⼴活动⻚⾯
- 游戏中的 Loading ⻚⾯
实现:
- 直接在当前 Window 上 addSubview
⻚⾯结构保证在最上⾯,didFinshLaunch方法内初始化UI之后。 - 创建新的 Window 成为 KeyWindow
调整 window 的 level 、多 Window 的管理
十、机型适配:
分三种:尺寸、像素和特殊机型
1、位置、⼤⼩、⽂字的适配(逻辑分辨率)
主要是针对不同屏幕的尺寸来决定是否按⽐例扩⼤
2、图⽚资源适配(物理分辨率)
根据像素密度来对图片进行2x 3x(缩放因⼦) 以及资源管理
资源管理有两种Bundle
和ImageAsset
Bundle:
- ⽅便管理和debug(以文件的绝对路劲)
- 删除和使⽤脚本
- 物理层⾯更⾼的灵活性
- 代码上通过语法糖实现特殊逻辑
ImageAsset:
- 系统应⽤瘦身 App thinning
- 不⽤写后缀,直接使⽤名字读取
- ⽅便管理,直观展示
- 改变颜⾊
3、iphoneX 适配
safeArea / 交互,包括statusbar、Home Indicator
Status Bar:
- 竖屏 20 -> 44
- 横屏 20
Home Indicator :
- 竖屏 34
- 横屏 21
Frame 布局 —— safeAreaInsets
- UIEdgeInsets
- 竖屏 { 44, 0, 34, 0 }
- 横屏 { 0, 44, 21, 44 }
4、 UIScreen & UIDevice
UIScreen:获取设备的逻辑尺⼨
- 基于硬件显示的相关属性
- [UIScreen mainScreen]
- 主要提供 size / 亮度 / 坐标系 等
适配⽅案选择
位置⼤⼩⽂字适配:
- 苹果官⽅ Human Interface Guidelines
- 更⼤设备显示更多内容
- 等⽐放⼤ 以 iPhone6 作为基准设计尺⼨
- iPhoneX 系列特殊的 UI 和交互
资源适配:
- 使⽤ @2x @3x 图⽚ / ⽹络数据处理
- pdf ⽮量图
- 使⽤合适的管理图⽚⽅式(Bundle / Asset)
UIDevice:获取设备的信息
- 操作系统 / 设备Model
- [UIDevice currentDevice]
- 设备⽅向 / 电量等
十一、APPs:
分为URL Scheme 和 Universal Link
URL Scheme :
1、使App能被其他App唤起
- 在
info
->URL Types
添加 - 在 UIApplication 中处理参数和业务逻辑
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
return YES;
}
2、通过 Scheme 唤起其它 App
- 通过 Scheme 判断 App 是否安装
[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@""]];
注意:这个方法生效的前提是必须在info
-> LSApplicationQueriesSchemes
的⽩名单数组中添加,canOpenURL
方法才会生效,否则返回NO
,且LSApplicationQueriesSchemes
的注册数量有限制。
- 使⽤ UIApplication 唤起 App
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@""] options:nil completionHandler:^(BOOL success) {
//处理业务逻辑
}];
Universal Link:
- 使⽤ HTTP / HTTPS 协议启动客户端
- Scheme重复 / Web 和 Native 统⼀
- 需要配合Web端进⾏注册
- 在Safari / 微信 / 其它 App 中使⽤Universal Link
十二、组件化
组件化方案对比十三、集成打包:
cocoapods
cocoapods是由Ruby语言编写的多项目集成工具,原理是把集成好的项目代码传到cocoapods,然后在要使用的项目里增加podfile文件,写好集成的第三方项目名、版本号等,然后pod install
,它会自动生成一个pod项目,并把pod.xcodeproj
和原来项目的projectName.xcodeproj
合并为一个projectName.xcworkspace
,这样项目就可以使用第三方的代码了。
注意:集成多项目后打开项目的入口是projectName.xcworkspace
,而不是projectName.xcodeproj
。
366