iOS开发的奇技淫巧

独奏

技术分享|2015-4-24|最后更新: 2023-2-23|
type
Post
status
Published
date
Apr 24, 2015
slug
summary
tags
category
技术分享
icon
password
最近好像这个话题很热啊,我不生产奇技淫巧我是大自然的搬运工

结构体简便初始化

// 不加(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}

三元条件表达式的两元使用

NSString *string = inputString ?: @"default"; NSString *string = inputString ? inputString : @"default"; // 等价
到这里让我想起了一个笑话
C有一个鲜为人知的运算符叫”趋向于”, 写作“–>”。比如说如果要实现一个倒数的程序,我们可以定义一个变量x,然后让它趋向与0:
#include <stdio.h> int main(int argc, char** argv) { int x = 10; while (x --> 0) { printf("%d ", x); } return 0; }
会打印出: 9 8 7 6 5 4 3 2 1 0

数组的下标初始化

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" };

可变参数类型的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回传回来的参数是什么,有几个。如一个对网络层的调用:
- (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:等类似方法中已经使用的相当好了。
+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock;

小括号内联复合表达式

A compound statement enclosed in parentheses原谅我的渣翻译- -,来自《gcc官方对此的说明》,源自gcc对c的扩展,如今被clang继承。
RETURN_VALUE_RECEIVER = ({ // Do whatever you want RETURN_VALUE; // 返回值 });
于是乎可以发挥想象力了:
self.backgroundView = ({ UIView *view = [[UIView alloc] initWithFrame:self.view.bounds]; view.backgroundColor = [UIColor redColor]; view.alpha = 0.8f; view; });
有点像block和内联函数的结合体,它最大的意义在于将代码整理分块,将同一个逻辑层级的代码包在一起;同时对于一个无需复用小段逻辑,也免去了重量级的调用函数,如:
self.result = ({ double result = 0; for (int i = 0; i <= M_2_PI; i+= M_PI_4) { result += sin(i); } result; });
这样使得代码量增大时层次仍然能比较明确。
PS: 返回值和代码块结束点必须在结尾

快捷的收键盘代码

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.view endEditing:YES]; }

去掉导航条返回键 title

[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60) forBarMetrics:UIBarMetricsDefault];

改变uitextfield placeholder的颜色和位置

- (void) drawPlaceholderInRect:(CGRect)rect { [[UIColor blueColor] setFill]; [self.placeholder drawInRect:rect withFont:self.font lineBreakMode:UILineBreakModeTailTruncation alignment:self.textAlignment]; }

电话 xxxx转xxxx

一般客服电话经常会出现需要转接分机的情况,比如 10010转6666 的形式,只需要如下的 URL scheme 就可以了:
tel:10010,6666
拨打的时候会首先拨通 10010,接通之后会紧接着按下6666四个数字

参考