美文网首页
iOS项目头文件改造

iOS项目头文件改造

作者: 庄msia | 来源:发表于2019-03-16 16:52 被阅读0次

    之所以会有这篇文章, 是因为最近Swift5出来后, 公司项目有意向往混编的方向走, 而纯Objc的老项目嘛...emmmm, 直接用的话转成Swift后真的一言难尽, 所以为了让公司其他人更好的改写用到的头文件, 就整理了一下难用的Nullability到底怎么用会比较方便, 顺便看了一下互相转换的宏哪个还用得上

    开始改造

    首先是Nullability, 先简单粗暴的用:

    NS_ASSUME_NONNULL_BEGIN
        
    NS_ASSUME_NONNULL_END
    

    把整个头文件包起来(import那几行不需要, 一般不包这几行)

    这样整个头文件所有类型都默认是非optional的

    然后再把需要变成可选的单独加上Nullability关键字即可:

    而考虑到各种问题, 比如官方一般用nullable, 而有些地方只能用__nullable, 所以最简单总结起来就是:
    1. 无脑类型后缀__nullable就好(block是在^后缀)
    2. _Nullable就不要碰了, 混在一起容易乱
    3. 至于property里跟不跟官方用nullable? 推荐写成CodeSnippet自动生成然后不要碰了(其实也就strong和copy需要nullable):
    @property (<#nullable, #>nonatomic, strong) <#Class#> *<#name#>;
    @property (<#nullable, #>nonatomic, copy) NSString *<#name#>;
    

    或者跟着官方的做法:

    1. 一般情况下无脑前缀nullable
    2. 遇到block相关的就类型后缀__nullable加以区分,也比较好记(block是在^后缀)
    3. _Nullable就不要碰了

    不管选哪个, 重点其实是整个项目保持一致性才是最重要的


    精致分割线


    如果上面的总结不能帮到你, 具体解释就是:

    1. __nullable/_Nullable是编译器参数,需要放到类型后面,也就是NSString *__nullable这样

    ps: OC里泛型是不能__nullable的, 我一时没想通傻试了好久, emmm...反应过来的时候差点笑死

    1. nullable是属性, 可以和strong/readonly一样放到property的括号里, 或者作为参数时和__weak一样前缀到变量类型前面:
    para:(nullable NSString *)name
    

    根据上面的规则就能衍变出:

    property有两种写法

    为了方便说明, copy/readonly这些称为property的属性

    @property (copy) NSString *__nullable name;
    
    @property (nullable, copy) NSString * name; // 本质还是前缀, 但property的属性需要写到括号里, 虽然这是官方写法, 但为了不要搞混最好不要记这个, 属性用CodeSnippet生成就好
    

    ps1: property还有一种nullable属性null_resettable

    字面意思就是setter可以传空, getter不能返回为空,编译器改写成Swift时会用!来表示, 如UIViewController.view就是null_resettable的:
    
    @property(null_resettable, nonatomic,strong) UIView *view;//这里复制过来就这样的,苹果少打了一个空格
    

    ps2: weak不能用nonnull

    方法的返回值和参数也各自有两种写法:
    - (NSString *__nullable)nameForItem:(NSString *__nullable)item;
    
    - (nullable NSString *)nameForItem:(nullable NSString *)item;// 官方也是这种写法, 还是那句话, 不要记这个
    

    最麻烦的是block

    block作为property

    它本身是不是optional需要在^后缀__nullable, 或者跟上面的property一样写成属性到括号里

    @property (copy) void (^__nullable aBlock)();
    
    @property (nullable, copy) void (^ aBlock)();
    
    block做参数也是两种写法:

    它本身是不是optioanl可以在^后缀__nullable, 前缀nullable, 但返回值和参数只能后缀__nullable

    - (void)needABlock:(id __nullable (^__nullable)(id __nullable para))aBlock;
    - (void)needABlock:(nullable id __nullable (^)(id __nullable para))aBlock;
    

    返回值前缀nullable会冲突这个很容易理解了, 所以反过来想, 大概是为了和返回值保持一致, 所以参数也只能后缀__nullable了吧...

    ps: 如果nulable的block是最后一个参数, Swift会自动转换成带默认值nil

    open func needABlock(_ aBlock: ((Any?) -> Void)? = nil)
    

    而普通类型的nullable变量则不会

    最后是block的typedef

    基本规则跟做参数是一样的, 但是定义这个type是不是optional跟做参数不同, 只能在^后缀__nullable(所以无脑类型后缀__nullable就好了):

    typedef id __nullable (^__nullable ABlock)(id __nullable para);
    
    还有一种 null_unspecified

    代表不确定是不是为空, 这个一般用不上, 总之大概跟nullable的用法差不多, 同样有编译器参数__null_unspecified/_Null_unspecified

    当既没有用ASSUME_NONNULL把头文件包起来, 也没有逐个添加Nullability时, 编译器就会默认用这个作为变量的Nullability

    如果真的不能确定到底会不会为空(以后可能会为空), 可以用这个, 编译器改写成Swift时会用!来表示(和null_resettable一样, 区别是OC里的警告不同), 如:

    @property (null_unspecified) id name;
    

    会被改写成:

    open var name: Any!
    

    接着还有一个用于命名的关键字是
    NS_SWIFT_NAME(<#swift专用名#>)
    可以用于任意内容, 包括类名, 属性名, 枚举:

    NS_SWIFT_NAME(VoiceFilter)
    @interface ABVoiceFilter : NSObject
    @end
    
    typedef NS_ENUM(NSUInteger, AType) {
        ATypeNone NS_SWIFT_NAME(NoneOne),
        ATypeOther NS_SWIFT_NAME(OtherPeople) ,
    };
    
    - (void)handleConnectItem:(id)connectionItem withParser:(id)parser NS_SWIFT_NAME(handle(item:parser:));
    

    相关文章

      网友评论

          本文标题:iOS项目头文件改造

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