iOS 指定初始化方法

作者: QiShare | 来源:发表于2019-05-13 18:27 被阅读80次

    级别: ★☆☆☆☆
    标签:「NS_DESIGNATED_INITIALIZER 」「NS_UNAVAILABLE」「iOS指定初始化方法」
    作者: WYW
    审校: QiShare团队


    前言:笔者最近了解了部分SDK开发相关的内容,在涉及指定视图控制器(下文用VC代指视图控制器)的初始化方法的时候,遇到了一些问题。这里笔者给大家分享下设置方法,如有不同见解,敬请指教。

    笔者遇到的问题如下:

    笔者希望 使用SDK的业务能够使用 SDK中确定的初始化VC的方法;
    下边笔者以需要传入VC的导航栏标题并初始化相应VC为例,来阐明相关问题。
    对于上述情况,有多种处理方式,如:

    1. 在SDK暴露的头文件中,文字说明,用哪个初始化方法;在文档中说明, 用哪个初始化方法;在提供的Demo中,写明相应地示例代码。
    2. 利用系统给的宏NS_DESIGNATED_INITIALIZER指定vc初始化方法
      指定初始化方法部分,可以使用宏NS_DESIGNATED_INITIALIZER指定,那么如果业务没有看SDK头文件,直接使用new 或者 alloc init的方式指定初始化方法,那么我们初始化VC所需的导航栏标题就不能得以正常传入。

    对于这种情况,我们可以提供如下3种方法:

    1. 把不想业务使用的初始化方法,使用系统宏 NS_UNAVAILABLE 把相应初始化方法设置为不可用;如禁用new ,这样的效果是:业务如果想使用new 初始化VC,会发现有错误提示,使用这种方法比较简单。
    1. 对于不想业务使用的初始化方法,在实现文件中,实现相应的方法,并且给予默认值。比如说对于初始化VC的导航栏标题的情况,给定默认标题为defaultNavigationTitle。不过这种初始化方法,不适用传入重要参数的情况,不然业务会觉得怪怪的。另外这种方式,以后如果有相关改动,可能改动代码会较多。
    1. 对于不想业务使用的初始化方法,在实现文件中,实现相应的方法,并且抛出崩溃,并且指定崩溃原因,在崩溃原因中说明应该使用的初始化VC的方法。对于这种方式,如果以后有改动,可能改动代码会较多。
      相比如上三种处理方式,笔者更倾向于使用第一种,如果你有其他见解,欢迎讨论。

    下边我们仍以初始化VC时,指定传入导航栏标题为例,贴上相关的示例代码。

    第一种方式:

    // .h 文件
    
    - (instancetype)initWithSomething:(id)someThing NS_DESIGNATED_INITIALIZER;
    
    - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE;
    - (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;
    - (instancetype)init NS_UNAVAILABLE;
    + (instancetype)new NS_UNAVAILABLE;
    
    // .m 文件
    
    /*! @brief 导航栏title */
    @property (nonatomic, copy) NSString *navTitle;
    
    
    - (instancetype)initWithSomething:(id)someThing {
        // Cannot assign to 'self' outside of a method in the init family
        // 指定初始化方法需要以 1. init开头 2. 并且init后边紧挨着地字母是大写的
        self = [super initWithNibName:nil bundle:nil];
        if (!self) {
            return nil;
        }
        _navTitle = someThing;
        [self commonInit];
        return self;
    }
    
    - (void)commonInit {
        
        self.navigationItem.title = _navTitle;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.view.backgroundColor = [UIColor whiteColor];
    }
    

    第二种方式:

    .h
    - (instancetype)initWithSomething:(id)someThing;
    
    
    // .m 文件
    
    /*! @brief 导航栏title */
    @property (nonatomic, copy) NSString *navTitle;
    
    
    - (instancetype)initWithSomething:(id)someThing {
        
        self = [super init];
        if (!self) {
            return nil;
        }
        _navTitle = someThing;
        return self;
    }
    
    - (instancetype)init {
        
        self = [super init];
        if (!self) {
            return nil;
        }
        [self commonInit];
        return self;
    }
    
    - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (!self) {
            return nil;
        }
        [self commonInit];
        return self;
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        
        self = [super initWithCoder:aDecoder];
        if (!self) {
            return nil;
        }
        [self commonInit];
        return self;
    }
    
    - (void)commonInit {
        
        _navTitle = @"Default";
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.navigationItem.title = _navTitle;
        self.view.backgroundColor = [UIColor whiteColor];
    }
    
    

    第三种方式:

    // .h 文件
    - (instancetype)initWithSomething:(id)someThing;
    
    
    // .m 文件
    static NSString *const kExceptionName = @"初始化方法有误";
    static NSString *const kExceptionReason = @"请使用initWithSomething:进行初始化";
    
    /*! @brief 导航栏title */
    @property (nonatomic, copy) NSString *navTitle;
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.navigationItem.title = _navTitle;
        self.view.backgroundColor = [UIColor whiteColor];
    }
    
    + (instancetype)new {
        
        @throw [[self class] initExceptioin];
        return nil;
    }
    
    - (instancetype)init {
        
        @throw [[self class] initExceptioin];
        return nil;
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        
        @throw [[self class] initExceptioin];
        return nil;
    }
    
    - (instancetype)initWithSomething:(id)someThing {
        
        self = [super init];
        if (!self) {
            return nil;
        }
        _navTitle = someThing;
        
        return self;
    }
    
    + (NSException *)initExceptioin {
        
        return [NSException exceptionWithName:kExceptionName reason:kExceptionReason userInfo:nil];
    }
    
    

    Demo:

    Demo:QiDesignatedInitializer

    参考学习网址


    小编微信:可加并拉入《QiShare技术交流群》。

    关注我们的途径有:
    QiShare(简书)
    QiShare(掘金)
    QiShare(知乎)
    QiShare(GitHub)
    QiShare(CocoaChina)
    QiShare(StackOverflow)
    QiShare(微信公众号)

    推荐文章:
    UIView中的hitTest方法
    iOS关于tabBar的几处笔记
    A的女儿是B的女儿的妈妈,A是B的谁?
    算法小专栏:选择排序
    iOS Runloop(一)
    iOS 常用调试方法:LLDB命令
    iOS 常用调试方法:断点
    iOS 常用调试方法:静态分析
    奇舞周刊

    相关文章

      网友评论

        本文标题:iOS 指定初始化方法

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