分析YYKit--宏定义的使用

****分析****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 。

分析YYKit--宏定义的使用_第1张图片
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:个人习惯,先找自己直接就能用的,然后再具体看...)

你可能感兴趣的:(分析YYKit--宏定义的使用)