美文网首页面试111iOS技能
分析YYKit--宏定义的使用

分析YYKit--宏定义的使用

作者: 李小争 | 来源:发表于2015-11-27 09:39 被阅读5454次

    ****分析****YYKit--****宏定义的使用**

    非常感谢ibireme的分享,代码真心赞.说实话对于开源其实我内心还是有点反感的,就像自己的孩子在大庭广众下被其他人赤裸裸地观赏.不过,受大家影响,我最近也打算分享些自己的东东.全当共同进步吧.

    回归正题,先分析下这份代码中我们直接拿来就能用的(做回伸手党😄).

    ****关于****block,****那就必须说****weak&strong

    一开始刚用block的时候直接在里面使用self,然后发现AFNetworking是这样使用的:

        __weak __typeof(self)weakSelf = self;
        AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
    
            strongSelf.networkReachabilityStatus = status;
            if (strongSelf.networkReachabilityStatusBlock) {
                strongSelf.networkReachabilityStatusBlock(status);
            }
    
        };
    

    学着AFN也就一直这样用.这次看到YYKit中怎么使用weak&strong的瞬间惊为天人.看下他是怎么用的.

    /**
     Synthsize a weak or strong reference.
     
     Example:
        @weakify(self)
        [self doSomething^{
            @strongify(self)
            if (!self) return;
            ...
        }];
    
     */
    #ifndef weakify
        #if DEBUG
            #if __has_feature(objc_arc)
            #define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
            #else
            #define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
            #endif
        #else
            #if __has_feature(objc_arc)
            #define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
            #else
            #define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
            #endif
        #endif
    #endif
    
    #ifndef strongify
        #if DEBUG
            #if __has_feature(objc_arc)
            #define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
            #else
            #define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
            #endif
        #else
            #if __has_feature(objc_arc)
            #define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
            #else
            #define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
            #endif
        #endif
    #endif
    

    这个可以直接拿来就用,已经使用在公司项目中了很方便.


    11月27日更新:

    ****新的认知****:****使用静态库的一些问题**

    宏定义来自YYKit,关于使用静态库的一些问题来自使用静态库的一些问题 -all_load

    1、使用类目
    在我们的静态库中涉及到 类目 catagory的使用时,会崩溃;
    此时我们需要设置project的Info里面的Link Flag处,增加-all _ load,这样会链接所以存在的symbol;
    这是我们常用的一种处理方法,除此之外我们还可以使用以下方法:
    若我们使用了类目

    "NSObject+SBJSON.h" 
    //我们在h,m文件分别增加以下声明
    @interface DummyClass_NSObject_SBJSON {} 
    @end 
    @implementation DummyClass_NSObject_SBJSON 
    @end 
    

    2、使用nib
    若封装静态库的时候我们使用了xib文件,亦有可能会出现此种形式的崩溃
    Unknown class XXX in Interface Builder file
    此处由于在代码中class XXX你并未引用过,具体的原理我也没有特别弄清楚,还希望高手帮助我们解释一下;
    我暂时做的处理时在接口处优先将这些 class 执行一个方法, 比如 [Class class];

    这个问题的原因应该是由于原先我的代码中并没有调用到 class XXX 相关方法;
    而静态库的一个优点是:链接器可以从静态库中只取出需要的部分来做链接。故没有链接 这些没有调用过方法的 class;
    暂时用上面的解决方案解决了,不知道有没有更好的方法来解决这个问题;
    以下两种情况都可以设置project的Info里面的Link Flag处,增加-all_load,解决

    在使用静态链接库时,如果出现一些莫名其妙的链接问题,如下提示:

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CPTMutableNumericData setDataType:]: unrecognized selector sent to instance 0x1edcee60'
    

    可尝试设置Link Flag 为 -all_load 。

    all_load.png

    下面这个宏就是YYKit中为了防止category出现上面问题

    /**
     Add this macro before each category implementation, so we don't have to use
     -all_load or -force_load to load object files from static libraries that only
     contain categories and no classes.
     More info: http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html .
     *******************************************************************************
     Example:
         YYSYNTH_DUMMY_CLASS(NSString_YYAdd)
     */
    #ifndef YYSYNTH_DUMMY_CLASS
    #define YYSYNTH_DUMMY_CLASS(_name_) \
    @interface YYSYNTH_DUMMY_CLASS_ ## _name_ : NSObject @end \
    @implementation YYSYNTH_DUMMY_CLASS_ ## _name_ @end
    #endif
    

    接上文...

    数值比较相关

    #ifndef YY_CLAMP // return the clamped value
    #define YY_CLAMP(_x_, _low_, _high_)  (((_x_) > (_high_)) ? (_high_) : (((_x_) < (_low_)) ? (_low_) : (_x_)))
    #endif
    

    这段宏定义主要就是确保值在两个值之间,如果经常需要进行数据判断的话,这个宏还是值得保留的.

    交换连个数值:

    #ifndef YY_SWAP // swap two value
    #define YY_SWAP(_a_, _b_)  do { __typeof__(_a_) _tmp_ = (_a_); (_a_) = (_b_); (_b_) = _tmp_; } while (0)
    #endif
    

    看到这里,我发现作者写的太细了,真想问下@ibireme 是不是处女座.

    ****断言****(NSAssert)

    关于NSAssert的使用来自这个链接,具体宏定义来自YYKit.

    苹果在foundation.framework中定义了这么一个宏:#define NSAssert(condition, desc, ...)

    第一个参数为一个条件判断,如果为假,则抛出异常,显示第二个参数所描述的信息。例如
    NSAssert(2>=4.4, @"2>=4.4 is false!");

    在debug模式下运行,会终止程序,并抛出如下异常:

    2013-04-24 09:24:16.618 TestAssertion[825:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '2>=4.4 is false!'
    

    在release模式下运行,不终止程序不抛出异常。
    这样方便调试程序。

    #define YYAssertNil(condition, description, ...) NSAssert(!(condition), (description), ##__VA_ARGS__)
    #define YYCAssertNil(condition, description, ...) NSCAssert(!(condition), (description), ##__VA_ARGS__)
    
    #define YYAssertNotNil(condition, description, ...) NSAssert((condition), (description), ##__VA_ARGS__)
    #define YYCAssertNotNil(condition, description, ...) NSCAssert((condition), (description), ##__VA_ARGS__)
    
    #define YYAssertMainThread() NSAssert([NSThread isMainThread], @"This method must be called on the main thread")
    #define YYCAssertMainThread() NSCAssert([NSThread isMainThread], @"This method must be called on the main thread"
    

    12月18日更

    内联函数

    在计算机科学中,内联函数(有时称作在线函数编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展);也就是说建议编译器将指定的函数体插入并取代每一处调用该函数的地方(上下文),从而节省了每次调用函数带来的额外时间开支。但在选择使用内联函数时,必须在程序占用空间和程序执行效率之间进行权衡,因为过多的比较复杂的函数进行内联扩展将带来很大的存储资源开支。另外还需要非常注意的是对递归函数的内联扩展可能带来部分编译器的无穷编译。来自维基百科

    简单点说:内联函数就是带参数的宏定义,当然有些区别,想了解具体的可以点击维基百科那个链接去看看.

    在YYKit中在YYKitMacro.h里面也有使用.
    例如:

    /**
     Convert CFRange to NSRange
     @param range CFRange @return NSRange
     */
    static inline NSRange YYNSRangeFromCFRange(CFRange range) {
        return NSMakeRange(range.location, range.length);
    }
    
    /**
     Convert NSRange to CFRange
     @param range NSRange @return CFRange
     */
    static inline CFRange YYCFRangeFromNSRange(NSRange range) {
        return CFRangeMake(range.location, range.length);
    }
    
    /**
     Same as CFAutorelease(), compatible for iOS6
     @param arg CFObject @return same as input
     */
    static inline CFTypeRef YYCFAutorelease(CFTypeRef CF_RELEASES_ARGUMENT arg) {
        if (((long)CFAutorelease + 1) != 1) {
            return CFAutorelease(arg);
        } else {
            id __autoreleasing obj = CFBridgingRelease(arg);
            return (__bridge CFTypeRef)obj;
        }
    }
    
    

    其实很多第三方都有使用比如AFN中:

    static inline NSString * AFMultipartFormInitialBoundary(NSString *boundary) {
        return [NSString stringWithFormat:@"--%@%@", boundary, kAFMultipartFormCRLF];
    }
    
    static inline NSString * AFMultipartFormEncapsulationBoundary(NSString *boundary) {
        return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF];
    }
    
    static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) {
        return [NSString stringWithFormat:@"%@--%@--%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF];
    }
    

    宏定义先到这里,开始进入程序里面看看.(ps:个人习惯,先找自己直接就能用的,然后再具体看...)

    相关文章

      网友评论

      • 梁森的简书:@weakify(self) 之后就直接使用self了是吗?
        李小争:不是,和Strong配合使用
      • 曾今的你:请教?__weak __typeof(self)weakSelf = self; 和 __weak typeof(self)weakSelf = self;写法有什么不同么
        李小争:效果一样
      • 沃尔德:我想很多人应该都没看过 这个 libextobjc
      • 处处闻笛鸟花落知多少谁知:您说 您看到YYKit中使用weak&strong的瞬间惊为天人。 我想问下@weakify里的@autoreleasepool{}是什么作用? :interrobang:
        ziooooo:在使用weakify,strongify的时候 前面可以加@符号,逼格更高,无实际用途
      • CNMD_LJ:weakify strongify 这些宏或类似的宏,国外很早就开始用了,也不只是ReactiveCocoa,并且ReactiveCocoa的用法不太一样,更加复杂的和隐晦
        阳光照耀下的范范:@塔格木洛洛 你们说的应该来自这里吧:https://github.com/jspahrsummers/libextobjc
        李小争:@塔格木洛洛 嗯,接触面有些窄,努力扩展中 :smile:
      • 孙大龙Lemon:不知道这家伙是从哪学
        李小争:@孙大龙Lemon 嗯,同样好奇.尤其是对图像理解那块
      • nuannuan_nuan:YY_CLAMP 这个宏定义是不是有误呀,如果宏定义中比较的high 为1 ,x为2, low为3,比较出来的就是错误额
        李小争:@暖暖的路 抱歉刚看到,最近有些忙.晚上看看
      • 冷漠叻荭颜:@weakify 和 @strongify ,ReactiveCocoa 中先就有了
        冷漠叻荭颜:@MarcyLi 哈哈,都是在学习
        李小争:@冷漠叻荭颜 :sweat:一直没接触过rac.谢谢提醒

      本文标题:分析YYKit--宏定义的使用

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