typeof

我们根据typeof()括号里面的变量,自动识别变量类型并返回该类型,typeof 常见运用于Block中,避免循环引用发生的问题。

weakSelf,block内部使用一次,引用计数不加1,self释放,weakSelf = nil


__weak __typeof(self) weakSelf = self;
  
  
weakSelf
LoginViewController *loginVC = [[LoginViewController alloc]init]; __weak __typeof(self) weakSelf = self; loginVC.loginFinished = ^(){ [weakSelf doSomeThing];//使用多次的话,就需要strongSelf }; [self.navigationController pushViewController:loginVC animated:YES];
strongSelf
    
    
LoginViewController *loginVC = [[LoginViewController alloc]init]; __weak __typeof(self) weakSelf = self;//block内部多次使用 loginVC.loginFinished = ^(){ __strong __typeof(self) strongSelf = weakSelf; [strongSelf doSomeThing]; [strongSelf doOtherThing]; }; [self.navigationController pushViewController:loginVC animated:YES];

其中比较有意思的地方就是先在block外定义一个弱引用的self指向self,然后在block内定义一个强引用的self指向weakSelf。那么就针对这两点来讲讲block里weak/strong self的问题。首先声明:上面提到的用法很保险,没有什么问题。

weakSelf->self 
我们都知道,block比较常见的一个问题就是循环引用问题,简单描述即:self已经持有了block,如果block里再使用self,self将被block截获,然后block持有self,导致循环引用。

那么我们在block外定义一个weakSelf指向self,然后block就会截获这个weakSelf,不会再产生循环引用的问题。

strongSelf->weakSelf 
block中还有个有意思的点就是block截获的变量在超出其作用域后仍能使用(比如block截获了self,然后block又被传递到其它地方使用,此时self按理已经释放)。这其实是因为系统会自动的根据情况将block从栈拷贝到堆中并强引用它截获的变量(一般我们的block最开始都是在栈中的),我们知道栈的内存是由系统管理的,而堆是由程序猿管理的,所以实现了变量超出作用域仍能使用。

根据这个说法,我们应该不需要自己强引用weakSelf,我们的weakSelf应该也会被block自己强引用,那我们何必多次一举呢…事实也确实如此,block确实强引用了我们的weakSelf,就算我们不自己强引用weakSelf代码也不会有问题。但是我们在上一段中提到了系统拷贝block是有条件的,有些条件下系统不会自动拷贝block,这种情况下weakSelf超出作用域将被释放。那么哪些情况下系统不会自动copy呢?最常见的一个——block作为参数传递,这也是使用频率非常高的一个点。所以,自己动手是为了更加保险。

下面列出block能够拷贝的情况: 
1、调用block的copy方法 
2、block作为返回值 
3、block赋值时 
4、Cocoa框架中方法名中含有usingBlock的方法 
5、GCD中

关于GCD中block再提一点: 
GCD中的block并没有直接或间接被self强引用的,所以不会存在循环引用,故不需要weakSelf;又GCD中block能够自动copy,所以self超出作用域仍可用,故不需要写strongSelf

总结: 
weakSelf是为了解决循环引用 
strongSelf是为了保证任何情况下self在超出作用域后仍能够使用

注意: typeof 括号中的值和等于后面的值是相同的类型。


self 宏定义

 
 
#define WeakSelf(weakSelf) __weak __typeof(&*self) weakSelf = self;
#define StrongSelf(strongSelf) __strong __typeof(&*self) strongSelf = weakSelf;

我们发现不止self需要使用weak,可能有部分变量也需要weak,于是我们的宏继续进化,不仅仅只支持self:

#define WeakObj(o) __weak typeof(o) o##Weak = o;
 
 
  • 1

这样,后续对需要使用weak的对象,只要写一句WeakObj(obj) 即可使用objWeak变量了(PS:发现没有,这里生成的变量名其实是objWeak,并不是weakObj,原因见文章末的注1)

再后来,我们发现了一些小技巧,可以让我们的这个宏看起来更原生一些,我们添加了@符号在前面:

#define WeakObj(o) autoreleasepool{} __weak typeof(o) o##Weak = o;
 
 
  • 1

使用上看起来是这样

@WeakObj(self);
...
[selfWeak doSomething];
 
 
  • 1
  • 2
  • 3

是不是感觉挺高大上的? 
这里是利用了@autoreleasepool{}这个系统的关键字来实现的,其实还可以利用@try{}@finally{}这个也可以达到相同的效果,比如:

#define WeakObj(o) try{}@finally{} __weak typeof(o) o##Weak = o;
 
 
  • 1

这部分空的@try或者空的@autoreleasepool会在编译时被优化掉,不必担心性能问题。


至此,我们的宏已经可以用了,但是实际使用中,出现了一个很尴尬的问题,就是代码自动补全,@W并不能自动提示出该宏,所以每次都是很尴尬的先利用提示,写完WeakObj(obj),然后光标移动到前面去打上一个@符号。 
这种事情怎么能忍受? 
还好我们还有利器,Xcode的CodeSnippet,任意方法内,写一句代码

@WeakObj(<#obj#>);
 
 
  • 1

拖到Xcode的CodeSnippet区域,快捷键设置为@WeakObj即可。 
这里写图片描述


strong宏,

#define StrongObj(o) autoreleasepool{} __strong typeof(o) o = o##Weak;
 
 
  • 1

用处嘛简单写个例子:

@WeakObj(self);
[var setBlock:^{
    @StrongObj(self);
    [self doSomething];
}];
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

最后,揭晓为什么该宏生成的变量名是objWeak: 
1. 使用时,如果开发者习惯性的要打出 [self doSomething]时,当他输入self时,自动补全出来的部分能看到还有selfWeak可供选择,算是一种提醒方式。 
2. 如果weak前置,当然也可以,生成的会是weakobj这样的变量名,只需要把宏中o##Weak 换成weak##o

宏定义:

#define YRWeakObj(o) autoreleasepool{} __weak typeof(o) o##Weak = o;
#define YRStrongObj(o) autoreleasepool{} __strong typeof(o) o = o##Weak;

typeof__typeof____typeof的区别


其实它们是没有区别的,只是它们只是针对不同的 c语言编译版本 有所不同的。
typeof是现代GNU C++的关键字;
从Objective-C的根源说,它其实来自于C语言,所以很多地方使用了继承自C的关键字。
看到AFNetworking 中,用的都是__typeof() ;

版权声明:本文为博主原创文章,欢迎转载但请保留文章出处。http://blog.csdn.net/u010124617




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值