美文网首页time
《禅与Objective-C编程艺术》阅读总结

《禅与Objective-C编程艺术》阅读总结

作者: 懒得起名的伊凡 | 来源:发表于2015-10-09 22:28 被阅读141次

    注:《Zen and the Art of the Objective-C Craftsmanship》 中文翻译版阅读总结

    原文在这里 ,感谢作者

    1、常量命名方法

    常量的命名方法 以驼峰法命名,并以相关类名作为前缀
    static const NSTimeInterval ZOCSignInViewControllerFadeOutAnimationDuration = 0.4;

    static NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification";

    常量在头文件中以这样的形式暴露给外部
    extern NSString *const ZOCCacheControllerDidClearCacheNotification;

    2、类名的规范

    (1)类名以是哪个大写字母作为前缀,双字母前缀为Apple的类预留。解决Objective-C没有命名空间所带来的问题。
    (2)创建一个子类时,把说明性的部分放在前缀和父类名的中间。如一个 UIViewController 的子类会是 ZOCTimelineViewController

    3、Initializer 和 dealloc

    (1)推荐将dealloc方法放在实现文件的最前面(直接在 @synthesize 以及 dynamic 之后),
    (2)为什么设置 self[super init] 的返回值?
    申请分配内存和初始化被分离为两步,allocinit。这个特性叫两步创建

    • alloc负责创建对象,这个过程包括分配足够的内存来保存对象,写入isa指针,初始化引用计数,以及重置所有实例变量。
    • init负责初始化对象,这意味着使对象处于可用状态。通常意味着为对象的实例变量赋予合理有用的值。

    alloc方法将返回一个有效的未初始化的对象实例。每一个对这个实例发送的消息会被转换成一次obj_msgSend()函数的调用,形参self的实参是alloc返回的指针,这样self在所有方法的作用域内都能够被访问。

    init方法可以通过返回 nil来告诉调用者,初始化失败了。

    4、Designated(指定) 和 Secondary (间接)初始化方法

    (1)designated 初始化方法是提供所有的参数,每一个类总有且只有一个。Seconary 初始化方法可以是一个或多个,他们仅仅是提供一个或者更多的默认参数来调用designated初始化的初始化方法。

    (2)在类继承中调用任何designated初始化方法都是合法的,应该保证所有的 designated initializer 在类继承中是从祖先(通常是NSObject)到你的类向下调用的。
    定义一个新类的三种方式:

    • 不需要重载任何的初始化函数
    • 重载 designated initializer
    • 定义一个新的 designated initializer

    第一个方案最简单,不需要天剑类的任何初始化逻辑,只需要依照父类的designated initializer

    @implementation YOEViewController
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // custom initialization(自定义的初始化过程)
        }
    return self;
    }
    

    第三种 希望提供自己的初始化函数时,遵循三个步骤来保证获得正确的行为:

    • 定义自己designated initializer,确保调用了直接超类的designated initializer
    • 重载直接超类的 designated initializer。调用新的 designated initializer
    • 为新的designated initializer写文档

    正确的实现例子:
    - (id)initWithNews:(NSString *)news
    {
    //call the immediate superclass's designated initializer(调用直接超类的designated initializer)
    self = [super initWithNibName:nil bundle:nil];
    if (self) {
    _news = news;
    }
    return self;
    }

    // Override the immediate superclass's designated initializer(重载直接父类的 designated initializer)
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        //Call the new designated initializer
        return  [self initWithNews:@"defaultNews"];
    }
    

    注:如果没有重载initWithNibName: bundle:方法,而调用者决定使用这个方法来初始化这个类(这是完全合法的)。initWithNews:永远也不会调用,这就导致了不正确的初始化流程,新类的特定初始化逻辑没有被执行。

    可以使用编译器的指令 NS_DESIGNATED_INITIALIZER__attribute__((objc_designated_initializer))来明确的支出那个方法是designated initializer。这样如果新的designated initializer没有调用超类的designated initializer,编译器会发出警告。

    写法:

    - (id)initWithNews:(NSString *)news __attribute__((objc_designated_initializer));
    
    - (id)initWithNews:(NSString *)news NS_DESIGNATED_INITIALIZER;
    

    通过另一个编译器指令attribute((unavailable("Invoke the designated initializer")))来修饰一个方法,这样会使在试图调用这个方法的时候产生一个编译错误(实际上代码提示都不会有该方法了)。
    写法:
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil attribute((unavailable("Invoke the designated initializer")));

    处理一个例外
    如果一个对象遵循NSCoding协议,并且它通过initWithCoder:初始化。此时应该看超类是否符合NSCoding协议来区别对待。符合的时候,如只是调用了[super initWithCoder:],就需要在designated initializer里面写一些通用的初始化代码,处理这种方法的是把这些代码放在私有方法里面。当超类不符合NSCoding协议的时候,推荐把initWithCoder:作为Secondary initializer来对待,并且调用self的designated initializer。

    5、单例的写法

    + (instancetype)sharedInstance
    {
        static id sharedInstance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedInstance = [[self alloc]init];
        });
        return sharedInstance;
    }
    

    6、属性定义

    (1)属性定义参数按顺序排列:原子性,读写,内存管理。
    @property(nonatomic,readwrite,copy) NSString *name;
    (2)属性可以存储一个代码块,必须使用copyblock最早在栈里面创建,使用copyblock拷贝到堆里面去。
    (3)声明一个公有的 getter 和一个私有的 setter,应该声明公开的属性为 readonly,并在类的扩展中重新定义属性为readwrite

    //.h文件中
    @interface YOEClass : NSObject
    
    @property(nonatomic,readonly,strong) NSObject *obj;
    
    @end
    
    //.m文件中
    @interface YOEClass ()
    
    @property(nonatomic,readwrite,strong) NSObject *obj;
    
    @end
    
    @implementation YOEClass
    
    - (id)init{
        self = [super init];
        if (self) {
            _obj = @"AA";
        }
        return self;
    }
    
    @end
    

    (4)声明一个BOOL属性,setter不应该带is前缀,对应的getter应该带上前缀,So:

    @property(assign,getter=isEditable) BOOL editable;
    

    注:在实现文件中应该避免使用@synthesize,编译器已经实现了

    7、NSNotification

    定义一个NSNotification 的时候,应该把通知的名字作为一个字符串常量

    //.h
    extern NSString * const ZOCFooDidBecomeBarNotification;
    //.m
    NSString * const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification";
    

    8、利用代码块

    代码块如果在闭合的圆括号里,会返回最后语句的值

    NSURL *url = ({
        NSString *urlStr = @"http://www.baidu.com";
        [NSURL URLWithString:urlStr];
    });
    

    9、self的循环引用

    当使用代码块和异步分发的时候,需要避免引用循环。应使用 weak 来引用对象,避免引用循环。

    __weak __typeof(self) weakSelf = self;
    

    例子:
    单个语句时:

     __weak __typeof(self) weakSelf = self;
    [self executeBlock:^(NSData *data, NSError *error) {
        [weakSelf doSomethingWithData:data];
    }];
    

    多个语句时:

    [self executeBlock:^(NSData *data, NSError *error) {
        __strong __typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf) {
            [strongSelf doSomethingWithData:data];
            [strongSelf doSomethingWithData:data];
        }
    }];
    

    简单记录self在block俩面的三种情况

    • 直接在block里面使用关键字 self。只能在 block 不是作为一个property 的时候使用,否则会导致 retain cycle。
    • 在 block 外定义一个 __weak 的引用到self,并且在 block 里面使用这个弱引用。 当 block 被声明一个 property 的时候使用。
    • 在block 外定义一个 __weak 的引用到 self,并且在 block 内部通过这个弱引用定义一个 __strong 的引用。 和并发执行有关。当涉及异步的服务的时候,block 可以在之后被执行,并且不会发生关于self是否存在的问题。

    相关文章

      网友评论

        本文标题:《禅与Objective-C编程艺术》阅读总结

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