美文网首页
(iOS) Objective-C

(iOS) Objective-C

作者: 布呐呐u | 来源:发表于2022-08-23 00:09 被阅读0次

    基础知识

    • nonatomic
    非原子属性,提高性能,但线程不安全
    
    • atomic
    原子属性,相对来说是线程安全,只是保证了setter和getter是线程安全,在异步函数中,也不是绝对安全,会降低性能
    
    
    • strong
    强引用,持有对象,引用计数 +1,相当于 MRC 环境中的 retain
    
    • copy
    强引用,持有对象,引用计数 +1
    
    • weak & assign
    weak 仅用于修饰对象,assign 也可以修饰对象,但多用于修饰基本数据类型
    
    相同点:
    weak 与 assign 都表示了一种"非拥有性关系",弱引用,不会影响引用计数
    
    不同点:
    被 weak 修饰的对象在销毁时会指向 nil 
    assign 修饰的对象则会造成野指针导致程序崩溃
    
    
    • Block
    block 3 种形态,
    没有使用外部变量时,属于全局区域,
    使用外部变量时,属于栈区域,栈区特点是内存随时会被系统回收,
    导致 crash 崩溃,因此要用 copy 修饰,copy 到堆区域后,
    不会函数执行完就销毁,会随着持有对象销毁而销毁
    
    copy 返回一个不可变类型,不会随外界改变而改变
    strong 有可能指向一个可变类型,会随外界改变而改变,故不能使用 strong 修饰
    
    

    进阶知识

    • UIView & CALayer
    UIView 是用来显示内容的,可以处理用户事件
    
    CALayer 是用来绘制内容的,对内容进行动画处理,依赖UIView来进行显示,不能处理用户事件
    
    UIView 来自CALayer,高于CALayer,是CALayer高层实现与封装
    
    • RunLoop
    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. */
        }
    }
    
    
    • KVC
    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】方法移除该键
    
    
    • KVO
    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
    事件链,包括事件传递链和事件响应链,当用户触发一个事件时,
    系统会将Event 打包加入到 UIApplication 消息队列中,
    然后传递到 window 对象,通过 【hitTest: withEvent】和【pointInside: withEvent】方法,
    判断当前操作是否在 window 窗口内,如果返回 true,则倒序遍历其子视图,
    找到最终响应的目标 view,完成事件传递与响应
    
     事件传递链
     UIApplication -> UIWindow -> rootViewController -> subView -> targetView
    
     事件响应链
     targetView -> parentView -> rootViewController -> UIWindow -> UIApplication
    
    

    相关文章

      网友评论

          本文标题:(iOS) Objective-C

          本文链接:https://www.haomeiwen.com/subject/nboigrtx.html