Source Code Learning - UITableView-FDTemplateLayoutCell

actionSheet 避开 switch case 写法

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    SEL selectors[] = {
        @selector(insertRow),
        @selector(insertSection),
        @selector(deleteSection)
    };

    if (buttonIndex < sizeof(selectors) / sizeof(SEL)) {
        void(*imp)(id, SEL) = (typeof(imp))[self methodForSelector:selectors[buttonIndex]];
        imp(self, selectors[buttonIndex]);
    }
}

利用判断条件或者在循环中调用某个方法的方式如上

已知函数名,有两种方式调用函数,之前在 SDWebImage 解析 中总结过可以使用 performSelector 或者 methodForSelector 两个函数。

do {} while(0) 在宏定义中的使用

static void __FD_TEMPLATE_LAYOUT_CELL_PRIMARY_CALL_IF_CRASH_NOT_OUR_BUG__(void (^callout)(void)) {
    callout();
}
#define FDPrimaryCall(...) do {__FD_TEMPLATE_LAYOUT_CELL_PRIMARY_CALL_IF_CRASH_NOT_OUR_BUG__(^{__VA_ARGS__});} while(0)

do{} while(0) 构造后宏的定义不会受到大括号、分号等影响。上面的使用方法展示了大括号问题,下面看看分号的影响。

#define foo(x) a(x); b(x)

这段代码本义是调用 foo 函数时指行 a 方法和 b 方法。但是如果你这样使用

if (isTrue) 
    foo(x);

那么宏扩展后变为

if (isTrue)
    a(x);
b(x);

那么改为下面这样呢

#define foo(x) { a(x); b(x); }

扩展后变为

if (isTrue) {
    a(x);
    b(x);
};

上面的方式又出现语法错误,所以修改为以下方式即可

#define foo(x) do { a(x); a(x); } while (0)

实现 NSCopying 协议限定

- (BOOL)existsHeightForKey:(id<NSCopying>)key;

id 限定参数 Key 必须实现了 NSCopying 协议

__kindof 返回一个子类实例

- (__kindof UITableViewHeaderFooterView *)fd_templateHeaderFooterViewForReuseIdentifier:(NSString *)identifier {
    // ...
}

 UITableViewHeaderFooterView *templateHeaderFooterView = [self fd_templateHeaderFooterViewForReuseIdentifier:identifier];

用 __kindof UITableViewHeaderFooterView 替换 id,明确表明了返回值的类型,又不需要调用的时候进行强制转换,只要 templateHeaderFooterView 是 UITableViewHeaderFooterView 的子类即可,不会出现警告,不再需要强制类型转换。

用枚举和数组设置变量

static const CGFloat systemAccessoryWidths[] = {
        [UITableViewCellAccessoryNone] = 0,
        [UITableViewCellAccessoryDisclosureIndicator] = 34,
        [UITableViewCellAccessoryDetailDisclosureButton] = 68,
        [UITableViewCellAccessoryCheckmark] = 40,
        [UITableViewCellAccessoryDetailButton] = 48
    };
contentViewWidth -= systemAccessoryWidths[cell.accessoryType];

给 Category 添加属性

_cmd 表示当前方法的selector

- (BOOL)fd_debugLogEnabled {
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}

可以注意下 Associated-objects 中有排小字:

Since SELs are guaranteed to be unique and constant, you can use _cmd as the key for objc_setAssociatedObject(). #objective-c #snowleopard

32 位和 64 位

#if CGFLOAT_IS_DOUBLE
    return number.doubleValue;
#else
    return number.floatValue;
#endif

NSNumber 中的浮点型变量取 double 还是 float 值,使用 CGFLOAT_IS_DOUBLE 判断,64 位的话则使用 double, 32 位的话则使用 float

参考文章

Runtime Programming Guide
do while in macros
Objectice - C 特性

请我喝汽水儿