最用心的转载了…

我是前言

看开源代码时,总会看到一些大神级别的代码,给人眼前一亮的感觉,多数都是被淡忘的C语言语法,总结下objc写码中遇到的各类非主流代码技巧和一些妙用:

  1. [娱乐向]objc最短的方法声明
  2. [C]结构体的初始化
  3. [C]三元条件表达式的两元使用
  4. [C]数组的下标初始化
  5. [objc]可变参数类型的block
  6. [objc]readonly属性支持扩展的写法
  7. [C]小括号内联复合表达式
  8. [娱乐向]奇葩的C函数写法
  9. [Macro]预处理时计算可变参数个数
  10. [Macro]预处理断言
  11. [多重]带自动提示的keypath宏

    [娱乐向]objc最短的方法声明

    先来个娱乐向的。
    方法声明时有一下几个trick:

返回值的- (TYPE)如果不写括号,编译器默认认为是- (id)类型:

 1. init;2. (id)init; // 等价于

同理,参数如果不写类型默认也是id类型:

 3. (void)foo:arg;4. (void)foo:(id)arg; // 等价于

还有,有多参数时方法名参数提示语可以为空

 5. (void):(id)arg1 :(id)arg2;6. (void)foo:(id)arg1 bar:(id)arg2; // 省略前

综上,最短的函数可以写成这样:

 7. _;   // 没错,这是一个oc方法声明8. :_;  // 这是一个带一个参数的oc方法声明
// 等价于9. (id)_;10. (id) :(id)_;

PS: 方法名都没的方法只能靠performSelector来调用了,selector是”:”

[C]结构体的初始化

// 不加(CGRect)强转也不会warning
CGRect rect1 = {1, 2, 3, 4};
CGRect rect2 = {.origin.x=5, .size={10, 10}}; // {5, 0, 10, 10}
CGRect rect3 = {1, 2}; // {1, 2, 0, 0}

[C]三元条件表达式的两元使用

三元条件表达式?:是C中唯一一个三目运算符,用来替代简单的if-else语句,同时也是可以两元使用的:

NSString *string = inputString ?: @"default";
NSString *string = inputString ? inputString : @"default"; // 等价

利用这个特性,我们还脑洞出了一个一行代码的 block 调用,平时我们的 block 是这样调用:

if (block0) {block0();
}
// or
if (block1) {int result = block1(1, 2);
}

居然可以简化成下面的样子:

!block0 ?: block0();
int result = !block1 ?: block1(1, 2);

[C]数组的下标初始化

const int numbers[] = {[1] = 3,[2] = 2,[3] = 1,[5] = 12306
};
// {0, 3, 2, 1, 0, 12306}

这个特性可以用来做枚举值和字符串的映射

typedef NS_ENUM(NSInteger, XXType){XXType1,XXType2
};
const NSString *XXTypeNameMapping[] = {[XXType1] = @"Type1",[XXType2] = @"Type2"
};

[objc]可变参数类型的block

一个block像下面一样声明:

void(^block1)(void);
void(^block2)(int a);
void(^block3)(NSNumber *a, NSString *b);

如果block的参数列表为空的话,相当于可变参数(不是void)

void(^block)(); // 返回值为void,参数可变的block
block = block1; // 正常
block = block2; // 正常
block = block3; // 正常
block(@1, @"string");  // 对应上面的block3
block(@1); // block3的第一个参数为@1,第二个为nil

这样,block的主调和回调之间可以通过约定来决定block回传回来的参数是什么,有几个。如一个对网络层的调用:

 11. (void)requestDataWithApi:(NSInteger)api block:(void(^)())block {if (api == 0) {block(1, 2);}else if (api == 1) {block(@"1", @2, @[@"3", @"4", @"5"]);}
}

主调者知道自己请求的是哪个Api,那么根据约定,他就知道block里面应该接受哪几个参数:

[server requestDataWithApi:0 block:^(NSInteger a, NSInteger b){// ...
}];
[server requestDataWithApi:1 block:^(NSString *s, NSNumber *n, NSArray *a){// ...
}];

这个特性在Reactive Cocoa-combineLatest:reduce:等类似方法中已经使用的相当好了。

 12. (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock;

[objc]readonly属性支持扩展的写法

@interface Sark : NSObject
@property (nonatomic, readonly) NSArray *friends;
@end

.m中可以使用_friends来使用自动合成的这个变量,但假如:

习惯使用self.来set实例变量时(只合成了getter) 希望重写getter进行懒加载时(重写getter时则不会生成下划线的变量,除非手动@synthesize) 允许子类重载这个属性来修改它时(编译报错属性修饰符不匹配)

这种readonly声明方法就行不通了,所以下面的写法更有通用性:

@interface Sark : NSObject
@property (nonatomic, readonly, copy/*加上setter属性修饰符*/) NSArray *friends;
@end

如想在.m中像正常属性一样使用:

@interface Sark ()
@property (nonatomic, copy) NSArray *friends;
@end

子类化时同理。iOS SDK中很多地方都用到了这个特性。

[C]小括号内联复合表达式

A compound statement enclosed in parentheses原谅我的渣翻译- -,来自《gcc官方对此的说明》,源自gcc对c的扩展,如今被clang继承。

RETURN_VALUE_RECEIVER = {(// Do whatever you wantRETURN_VALUE; // 返回值
)};

于是乎可以发挥想象力了:

self.backgroundView = ({UIView *view = [[UIView alloc] initWithFrame:self.view.bounds];view.backgroundColor = [UIColor redColor];view.alpha = 0.8f;view;
}); // 我的这篇博客就用到这个写法[iOS 一步一步带你实现引导页]

有点像block和内联函数的结合体,它最大的意义在于将代码整理分块,将同一个逻辑层级的代码包在一起;同时对于一个无需复用小段逻辑,也免去了重量级的调用函数,如:

self.result = ({double result = 0;for (int i = 0; i <= M_2_PI; i+= M_PI_4) {result += sin(i);}result;
});

这样使得代码量增大时层次仍然能比较明确。
PS: 返回值和代码块结束点必须在结尾

[娱乐向]奇葩的C函数写法

int sum(a,b)
int a; int b;
{return a + b;
}

[Macro]预处理时计算可变参数个数

#define COUNT_PARMS2(_a1, _a2, _a3, _a4, _a5, RESULT, ...) RESULT
#define COUNT_PARMS(...) COUNT_PARMS2(__VA_ARGS__, 5, 4, 3, 2, 1)
int count = COUNT_PARMS(1,2,3); // 预处理时count==3

[Macro]预处理断言

下面的断言在编译前就生效

#define C_ASSERT(test) \switch(0) {\case 0:\case test:;\}

如断言上面预处理时计算可变参数个数:

C_ASSERT(COUNT_PARMS(1,2,3) == 2);

[多重]带自动提示的keypath宏

源自Reactive Cocoa中的宏:

#define keypath2(OBJ, PATH) \(((void)(NO && ((void)OBJ.PATH, NO)), # PATH))

《介绍RAC宏的文章》

逗号表达式

逗号表达式取后值,但前值的表达式参与运算,可用void忽略编译器警告

int a = ((void)(1+2), 2); // a == 2

逻辑最短路径

之前的文章没有弄清上面宏中NO&&NO的含义,其实这用到了编译器优化的特性:

if (NO && [self shouldDo]/*不执行*/) {// 不执行
}

编译器知道在NO后且什么的结果都是NO,于是后面的语句被优化掉了。也就是说keypath宏中这个NO && ((void)OBJ.PATH, NO)就使得在编译后后面的部分不出现在最后的代码中,于是乎既实现了keypath的自动提示功能,又保证编译后不执行多余的代码。
References
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

原文链接by@sunnyxx

objc非主流代码技巧相关推荐

  1. Objective-C 非主流代码技巧

    我是前言 看开源代码时,总会看到一些大神级别的代码,给人眼前一亮的感觉,多数都是被淡忘的C语言语法,总结下objc写码中遇到的各类非主流代码技巧和一些妙用: [娱乐向]objc最短的方法声明 [C]结 ...

  2. 敲代码就是一把梭_2020必看!开发五年的大佬日常工作中所使用的java代码技巧...

    前言 罗列工作中实际使用的一些代码技巧或者叫工具类;知识无大小,希望大家都有收获 实用技巧 rpc服务出参统一化 什么,出参统一化有什么好说的????? 我不知道你们有没有遇到过多少五花八门的外部服务 ...

  3. 13 种 JavaScript 代码技巧

    13 种 JavaScript 代码技巧 1. 多表达式多 if 判断 我们可以在数组中存储多个值,并且可以使用数组include方法. // 长 if (x === 'abc' || x === ' ...

  4. 编写高效的PyTorch代码技巧(下)

    点击上方"算法猿的成长",关注公众号,选择加"星标"或"置顶" 总第 133 篇文章,本文大约 3000 字,阅读大约需要 15 分钟 原文 ...

  5. server接收dtu透传代码_Gopher2020大会干货总结:代码技巧篇

    Gopher2020大会已经结束了几天,圈内大牛的分享可谓干货满满,分享内容涉及到诸多的业务.框架.理念等,本文系会后粗略整理,主要是将一些干货内容总结.分类:本文内容不涉及业务.框架以及设计理念,整 ...

  6. seqkit根据基因id_ID转换靠的是深厚的背景知识加上一点代码技巧

    有学员提问: 请教老师,在分析一个芯片数据时候,遇到这个GPL16686平台,直接看平台信息里面的表格如图,找不到基因名,所以不知道该怎么办,ID转换就卡死了,后续的差异分析,火山图,热图等等都无从下 ...

  7. Soul源码分析 ——值得借鉴的代码技巧

    Soul源码分析 -- 可以复用的代码技巧 对bean的操作 设计模式的使用 线程池 线程池线程数 拒绝策略 SPI 加载工厂 java spi应用 自己实现spi Soul-common模块里所有工 ...

  8. 校内代码 xiaonei代码 xiaonei黑色非主流代码

    校内代码 xiaonei代码 xiaonei黑色非主流代码 http://xioonei.cn

  9. spring中那些让你爱不释手的代码技巧

    紧接上文<spring中这些能升华代码的技巧,可能会让你爱不释手>.本文继续总结我认为spring中还不错的知识点,希望对您有所帮助. 一. @Conditional的强大之处 不知道你们 ...

最新文章

  1. Koltin 高阶函数
  2. My97DatePicker日历控件日报、每周和每月的选择
  3. Java 高并发面试题
  4. Android App“加固”
  5. ZABBIX3.0配置邮件报警
  6. 彻底理解链接器:二,符号决议
  7. 第一百五十二期:白话Entity Framework Core数据验证
  8. 云麦小米华为体脂秤怎么样_测评华为智能体脂秤,比小米智能体重秤贵30元到底差别在哪里?...
  9. 【ElasticSearch】Es 源码之 SearchService 源码解读
  10. php中的数据库操作类、分页类,以及smarty扩展类
  11. docker(podman)命令参考
  12. Centos解决ppp: compressor dropped pkt
  13. POJ 1947 Rebuilding Roads
  14. php微信投票刷票,微信投票程序源码
  15. 风灵月影捆绑软件解决办法(修改器)
  16. 多次复制粘贴工具Paste Queue Mac
  17. 概念模型转化为逻辑模型规律
  18. PHP修改图片像素大小
  19. 科学论文的写作内容与要求
  20. SecureCRT查看日志乱码

热门文章

  1. 计算机构弹性振动振型的软件,《PKPM软件在应用中的问题解析》讲义(十九)
  2. 澳网见证三巨头书写伟大时代 中国军团多点开花
  3. 小米平板6什么时候上市?2023年参数配置发布时间最新消息一览
  4. CorelDRAW2022全新试用版功能详细讲解
  5. 【阿里聚安全·安全周刊】阿里安全潘多拉实验室完美越狱iOS11.2.1|Janus漏洞修改安卓app而不影响签名...
  6. html邮件加入退订链接,Word邮件和网页技巧:取消自动转换的超级链接-word技巧-电脑技巧收藏家...
  7. php的主要功能有哪些,php常用功能有哪些?
  8. 使用面向对象的思想,编写自定义描述狗的信息。设定属性包括:品种,年龄,心情,名字;方法包括:叫,跑
  9. 恕我直言,你可能被支付宝账单预测关键词骗了!
  10. 程序员应该怎么和女生聊天,哪些话题屡试不爽?