__weak typeof(self) weakSelf = self的应用
typeof(xxx)是用来确定括号中内容的类型,如
int a = 10;
可以这样写
typeof(100) a = 10;
这两种写法是等价的。那么回到上边,__weak typeof(self) weakSelf 可以用其它代码代替。假如self为PersonViewController,那么
__weak PersonViewController *weakSelf = self;
这两种也是等价的,只不过用typeof不用管那么多。
意思是声明了一个self类型的weakSelf,加上__weak表示它是弱引用的。整行代码就是给self定义了一个弱引用性质的替身。
一般用在block上,因为block会copy它内部的变量,可能会造成循环引用,使用__weak性质的self代替self,可以切断block对self的应用,避免循环使用。如
1 if (nil == error) {
2 __weak typeof(self) weakSelf = self;
3 dispatch_async(dispatch_get_global_queue(0, 0), ^{
4 /*异步解析*/
5 NSArray *array = EncodeArrayFromDic(jsonItems,@"data");
6
7 NSMutableArray *arrayDtos = [NSMutableArray array];
8 for (NSDictionary *item in array) {
9 DocMsgModel *dto = [DocMsgModel parser:item];
10 if (nil != dto) {
11 [arrayDtos addObject:dto];
12 }
13 }
14
15 dispatch_async(dispatch_get_main_queue(), ^{
16 [weakSelf.delegate manageMainView];
17 });
18 });
19 }
block可以把函数当做属性来声明,虽然也可以直接在.h中写方法,这两种写法作用是一样的,只是写法不同。如下
在TableCell.h中
1 @property (nonatomic,strong) UIView *cellDownBg;
2 @property (nonatomic,copy) void(^deleteBtnClickBlock)(NSString *contentID);
3 //该block写法和下边的作用一样
4 //-(void)deleteBtnClick:(NSString *)contentId;
然后使用block时还需设置self(指的是controller)为weak型。
在controller的.m中,
1 -(void)someFunction{
2 __weak typeof(self) weakSelf = self;
3 TableCell *cell = [[TableCell alloc] init];
4 cell.deleteBtnClickBlock = ^(NSString *contentID){
5 [weakSelf deleteContentWithContentId:contentID];
6 }
7 }
下面说下block比较详细的用法
第一部分:block形式
block有三种形式,关于参数和返回值的。
①无参数,无返回值
-(void)viewDidLoad {
[super viewDidLoad];
void(^printSth)() = ^(){
printf("没有数字
");
}
printSth();
}
打印结果为:
②有参数,无返回值
-(void)viewDidLoad {
[super viewDidLoad];
printTheNum(55);
}
void(^printTheNum)(int) = ^(int val){
printf("the num is %d
",val);
};
打印结果为:
③有参数,有返回值
-(void)viewDidLoad {
[super viewDidLoad];
int localNum = 7;
int (^printElse)(int) = ^(int num){
return num * localNum;
};
int newNum = printElse(3);
printf("new localNum is %d
",newNum);
}
打印结果为:
由上可以看出,block既可以定义在方法(如viewDidLoad)内部,也可以定义在方法外部。
第二部分:__block关键字的使用
在block的{}内,是不可以对外面的变量进行赋值的。如:
1 - (void)viewDidLoad {
2 [super viewDidLoad];
3
4 int localNum = 7;
5 int (^myBlock)(int) = ^(int num){
6 localNum = num * 3;
7 return num * localNum;
8 };
9 }
此时会有Variable is not assignable (missing __block type specifier)的错误提示。
加上__block,就可以修改了。
第三部分:不同类间的传值
block作用如同函数,当用作property时,可以在两个类之间传值。如:
两个controller,分别为A和B,A中有label,B中有textfield。当跳往B后,点击按钮再返回A。label显示textfield的内容。
①用delegate实现
在B的.h中
@protocol ThirdViewControllerDelegate <NSObject>
@optional
-(void)transferTheVal:(NSString *) textVal;
@end
@interface ThirdViewController : UIViewController
@property(nonatomic,assign) id<ThirdViewControllerDelegate> delegate;
@end
在B的.m中
-(void)clickTheBtn{
[self.navigationController popViewControllerAnimated:YES];
if (self.delegate && [self.delegate respondsToSelector:@selector(transferTheVal:)]) {
[self.delegate transferTheVal:self.textFirldAll.text];
}
}
在A的.m中
@interface ViewController ()<ThirdViewControllerDelegate>
@property(nonatomic,strong) UILabel *myLab;
@end
-(void)transferTheVal:(NSString *)textVal{
self.myLab.text = textVal;
}
②用block实现
在B的.h中
@interface NextViewController : UIViewController
@property(nonatomic,strong) UITextField *textFirldAll;
@property(nonatomic,copy) void(^nextControlBlock)(NSString *textVal);
@end
在B的.m中
-(void)clickTheBtn{
[self.navigationController popViewControllerAnimated:YES];
if (self.nextControlBlock) {
self.nextControlBlock(self.textFirldAll.text);
}
}
在A的.m中
1 -(void)clickTheBtn{
2 NextViewController *nextVC = [[NextViewController alloc] init];
3 [self.navigationController pushViewController:nextVC animated:YES];
4 __weak typeof(self) weakSelf = self;
5 //block中应为weak型的self,防止循环引用
6 nextVC.nextControlBlock = ^(NSString *textVal){
7 [weakSelf resetTextVal:textVal];
8 };
9 }
10
11 -(void)resetTextVal:(NSString *)newVal{
12 self.myLab.text = newVal;
13 }
由此可以看出delegate和block两种用法的异同
************************** 2015-10-08 补充 **************************
block也可以在函数中使用,作为参数类型。
//参数为changed,类型为void(^)(void)
- (void)doSth:(void(^)(void))changed;
//参数squre的类型为int(^)(int)型
-(void)objcMethod:(int(^)(float))squre;
使用时有
- (void)doSth:(void(^)(void))changed{
//其它的其它操作
//执行block
changed();
}
-(void)objcMethod:(int(^)(float))squre{
squre(3.0);
}
void(^)(void)表示无参数无返回值,int(^)(float)表示参数为float,返回值为int
由这两种写法可以看出,当block作为参数类型时,代码格式---中间的(^)是必须的
使用block需要注意的问题
①在调用block时必须做非空判断,否则会崩溃
void (^logPrint)() = ^{
NSLog(@"*********");
};
if (nil != logPrint) {
logPrint();
}
②对于比较长的block,尽量用typedef定义新的名称来代替block。typedef的用法如下:
typedef int MyInt;
//与int a = 10 等价
MyInt a = 10;
意为将int类型用MyInt代替,这样比较直观。对于block类型,写法不太一样。
//两数相加
int(^plusNum)(int,int) = ^(int a,int b){
return a+b;
};
//两数相减
int(^minusNum)(int,int) = ^(int a,int b){
return a-b;
};
用typedef重新定义
typedef int(^twoNum)(int num1,int num2);
表示返回值为int类型,参数有两个,且都为int类型,block名称为twoNum。
使用时可以
-(void)viewDidLoad{
[super viewDidLoad];
//两数相加
twoNum plusNu = ^(int a,int b){
return a + b;
};
//两数相减
twoNum minusNu = ^(int a,int b){
return a - b;
};
plusNu(4,2);
minusNu(3,5);
}
对于对象类型的block,有参数有返回值的写法
NSString * (^myName)(NSString *a,NSString *b) = ^(NSString *firstName,NSString *lastName){
NSString *name = [firstName stringByAppendingString:lastName];
NSLog(@"my Name is %@",name );
return name;
};
用typedef定义时
typedef NSString * (^MyName) (NSString *firstName,NSString *lastName);
-(void)viewDidLoad{
[super viewDidLoad];
MyName nameL = ^(NSString *firstName,NSString *lastName){
NSString *name = [firstName stringByAppendingString:lastName];
NSLog(@"----%@",name);
return name;
};
nameL(@"Xi",@"Li");
}
可以看出,作用一样,只是形式上更简洁。尽量使用typedef这种写法。
*********** 2016-04-12补充 *****************
block作为代码块,可以用在属性、方法中。示例如下:
#pragma mark —— block作为属性
//无参数,无返回值
@property(nonatomic,copy) void(^test1)();
//无参数,有返回值
@property(nonatomic,copy) NSString *(^test2)();
//有参数,有返回值
@property(nonatomic,copy) NSString *(^test3)(NSString *firstName,NSString *lastName);
#pragma mark —— block作为方法的参数
//无参数,无返回值
-(void)testOne:(void(^)()) testBlock;
//无参数,有返回值
-(void)testTwo:(NSString *(^)()) testBlock;
//有参数,有返回值
-(void)testThree:(NSString *(^)(NSString *num1,NSString *num2)) testBlock;