(iOS) Objective-C

2022-08-23  本文已影响0人  布呐呐u

基础知识

非原子属性,提高性能,但线程不安全
原子属性,相对来说是线程安全,只是保证了setter和getter是线程安全,在异步函数中,也不是绝对安全,会降低性能

强引用,持有对象,引用计数 +1,相当于 MRC 环境中的 retain
强引用,持有对象,引用计数 +1
weak 仅用于修饰对象,assign 也可以修饰对象,但多用于修饰基本数据类型

相同点:
weak 与 assign 都表示了一种"非拥有性关系",弱引用,不会影响引用计数

不同点:
被 weak 修饰的对象在销毁时会指向 nil 
assign 修饰的对象则会造成野指针导致程序崩溃

block 3 种形态,
没有使用外部变量时,属于全局区域,
使用外部变量时,属于栈区域,栈区特点是内存随时会被系统回收,
导致 crash 崩溃,因此要用 copy 修饰,copy 到堆区域后,
不会函数执行完就销毁,会随着持有对象销毁而销毁

copy 返回一个不可变类型,不会随外界改变而改变
strong 有可能指向一个可变类型,会随外界改变而改变,故不能使用 strong 修饰

进阶知识

UIView 是用来显示内容的,可以处理用户事件

CALayer 是用来绘制内容的,对内容进行动画处理,依赖UIView来进行显示,不能处理用户事件

UIView 来自CALayer,高于CALayer,是CALayer高层实现与封装
RunLoop 是 iOS 系统最核心的机制,APP应用启动后,会默认创建主线程的 RunLoop

1)保持程序的持续运行;
2)节省CPU资源,提高程序性能,该做事时做事,没事时休息;
3)处理App中的各种事件(如:触摸事件、定时器事件、Selector事件);


如何启用:调用 run 方法,启用子线程 RunLoop

线程常驻:调用 addPort 方法,使线程常驻

1)@autoreleasepool 是自动释放池,使我们更灵活的管理内存;
2)使用 @autoreleasepool {  custom code } 创建自动释放池,随后自动释放内存;

3)官网中,一个自动释放池使用场景的例子
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
 
    @autoreleasepool {
        NSError *error;
        NSString *fileContents = [NSString stringWithContentsOfURL:url
                                         encoding:NSUTF8StringEncoding error:&error];
        /* Process the string, creating and autoreleasing more objects. */
    }
}

Key-Value-Coding(键值编码)

存值
1)当某个对象调用 【setValue:forKey】方法时
2)判断该对象有没有指定 Key 的 setter 方法,若存在,则直接调用 setter 方法进行赋值
3)若不存在,则按照 "_Key,_isKey,Key,isKey" 顺序依次查找,找到后直接对该属性进行赋值
4)如果都没有找到,则会执行【setValue: forUndefinedKey】方法,并抛出异常

取值
1)当某个对象调用 【valueForKey: 】方法时
2)判断该对象有没有指定 Key 的 getter 方法,若存在,则直接调用 getter 方法获取值
3)若不存在,则按照 "_Key,_isKey,Key,isKey" 顺序依次查找,找到后直接读取该属性值
4)如果都没有找到,则会执行【valueForUndefinedKey:】方法,并抛出异常

对于 NSDictionary
当调用 【setValue:forKey】时,相当于调用了 【setObject: forKey】
当值为 nil 时,则会调用【removeObject:ForKey】方法移除该键

Key-Value-Observing(键值观察)

KVO 是基于 runtime 机制实现的
通过 setter 方法或KVC赋值,才可以触发KVO机制
直接修改成员变量值,不会触发KVO【例如  _name = @"newName" 】
添加KVO后,要在合适时机移除KVO

1)当对 Person 对象中的 name 属性进行监听观察时
2)系统会自动生成一个继承于 Person 名为 NSKVONotifying_Person 的子类
3)在子类的中,重写 setName方法

  - ( void)setName:( NSString*)newName {
  // 被观察属性值,改变之前调用
   [ self willChangeValueForKey: @"name"];

   // 调用父类的set方法 
  [ super setValue:newName forKey: @"name"]; 

  // 被观察属性值,改变之后调用
  [ self didChangeValueForKey: @"name"];
  
  }

4)通过此方法,处理观察值发生改变的相关逻辑 
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context 

5)手动触发 KVO
  willChangeValueForKey 
  didChangeValueForKey 

事件链,包括事件传递链和事件响应链,当用户触发一个事件时,
系统会将Event 打包加入到 UIApplication 消息队列中,
然后传递到 window 对象,通过 【hitTest: withEvent】和【pointInside: withEvent】方法,
判断当前操作是否在 window 窗口内,如果返回 true,则倒序遍历其子视图,
找到最终响应的目标 view,完成事件传递与响应

 事件传递链
 UIApplication -> UIWindow -> rootViewController -> subView -> targetView

 事件响应链
 targetView -> parentView -> rootViewController -> UIWindow -> UIApplication

上一篇 下一篇

猜你喜欢

热点阅读