本文是本人平时开发遇到的三方库的填坑记录,仅做保存,如果有误导嫌疑,请无视我。
一、ReactiveCocoa
1、block是被控制器持有的,如果在block中使用self,会引起循环引用,控制器不能被释放掉,所以不是所有的三方库的block都是做了处理的。
block中,会引起循环引用有以下几种情况:
//(1)在block中,使用self调用方法
object.delegatrSignal = [RACSubject subject];
[object.delegatrSignal subscribeNext:^(id x) {
//使用self调用方法
[self doSomething];
}];
//应使用weak修饰self,避免相互循环引用
__weak typeof(self) weakSelf = self;
object.delegatrSignal = [RACSubject subject];
[object.delegatrSignal subscribeNext:^(id x) {
//使用self调用方法
[weakSelf doSomething];
}];
//(2)在block中,使用self的成员变量
object.delegatrSignal = [RACSubject subject];
[object.delegatrSignal subscribeNext:^(id x) {
// 注:经过测试,在block中不通过self.property的方式调用,通过_property的方式调用,都会引起循环引用
self.property;
_property;
}];
//同样应使用weak修饰self,避免相互循环引用
__weak typeof(self) weakSelf = self;
object.delegatrSignal = [RACSubject subject];
[object.delegatrSignal subscribeNext:^(id x) {
weakSelf.property;
}];
//(3)在block中直接使用类的私有成员变量也会造成循环引用:
//例如ViewController中有一个block类型的成员属性someBlock,另外一个是私有变量_children:
@interface ViewController : UIViewController
{
NSObject *property;
}
@property (copy, nonatomic) void(^someBlock)();
//其实在默认情况下,ViewController中的_children是使用__strong修饰的,上述情况就等价于下面的代码:
@interface ViewController : UIViewController
{
__strong NSObject *property;
}
@property (copy, nonatomic) void(^someBlock)();
//这个时候,在为someBlock赋值的时候,直接使用property就会造成retain cycle:
self.someBlock = ^{
property;
// 上面代码就等价于下面一行
// self->property;
};
//要打破此循环引用,也要用到(1)中使用的方法,不同的是,必须在block内使用__strong的self:
__weak typeof(self) weakSelf = self;
self.someBlock = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf->property;
};
// __weakSelf在block里面有可能执行完一次被释放,所有要用__strong来确保在block内weakSelf不会被释放,但是此block内只有一句话,为什么要用__strong呢?因为用weakSelf->会引发这一种错误:Dereferencing a __weak pointer is not allowed due to possible null value caused by race condition, assign it to a strong variable first. (对一个 __weak 指针的解引用不允许的,因为可能在竞态条件里面变成 null, 所以先把他定义成 strong 的属性),所以必须用__strong来确保为强引用
注:
经过查阅资料,找到RAC下避免循环引用的方法:
#import "RACEXTScope.h"
- (void)viewDidLoad
{
[super viewDidLoad];
@weakify(self);
[[NSNotificationCenter defaultCenter] addObserverForName:@"key" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
@strongify(self);
[self doSomething];
// 如果使用到self的属性,不能用下划线_property,必须用self.property的方式
}];
}
二、支付宝SDK
1、调用支付宝SDK跳转方法中的回调block中,也容易导致retain cycle,在回调block中不能直接使用self调用方法,或者直接使用成员变量和私有变量,调用方法如下:
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
}];
解决方法见上方ReactiveCocoa第一条。
2018.3.15更新
三、MJRefresh 刷新提示文本变为大写英文字母
在pod过的MJRefresh的项目中,Xcode9上,刷新提示文本变为大写英文字母,没有进行本地化处理。初步估计是本地化Localizable.strings文件在项目中没有成功加载。只有自己添加一遍来解决。
解决办法:
1、添加本地化文件 Localizable.strings,确保添加中英文。 添加方法
2、将一下文本复制在简体中文的文件中:
"MJRefreshHeaderIdleText" = "下拉可以刷新";
"MJRefreshHeaderPullingText" = "松开立即刷新";
"MJRefreshHeaderRefreshingText" = "正在刷新数据中...";
"MJRefreshAutoFooterIdleText" = "点击或上拉加载更多";
"MJRefreshAutoFooterRefreshingText" = "正在加载更多的数据...";
"MJRefreshAutoFooterNoMoreDataText" = "已经全部加载完毕";
"MJRefreshBackFooterIdleText" = "上拉可以加载更多";
"MJRefreshBackFooterPullingText" = "松开立即加载更多";
"MJRefreshBackFooterRefreshingText" = "正在加载更多的数据...";
"MJRefreshBackFooterNoMoreDataText" = "已经全部加载完毕";
"MJRefreshHeaderLastTimeText" = "最后更新:";
"MJRefreshHeaderDateTodayText" = "今天";
"MJRefreshHeaderNoneLastDateText" = "无记录";
。。。未完待续