iOS -- block

 Block:一種匿名函數,能夠捕獲周圍的變量

Block是一種匿名函數,Block中能夠保存一段代碼,它能夠做爲參數、做爲返回值,在須要的時候調用。經常使用於GCD、動畫、各類回調ios

 

block 在實現時就會對它引用到的它所在方法中定義的局部變量進行一次只讀(const)拷貝,而後在 block 塊內使用該只讀拷貝程序員

NSString * functionName = @"functionName";
    
    NSString * (^testBlock)(NSString *) = ^NSString * (NSString * name){
        
        myName = @"nana";
//        functionName = @"fff";    //報錯,不能改變自動變量的值
        self.vcName = @"vvvvv";  //沒有報錯,能夠改變變量的值
        
        NSLog(@"%@",name);
        return name;
    };
    testBlock(@"cc");

 若是想要在block裏改變局部變量的值,能夠用__block修飾符面試

__block int val = 10;  
void (^blk)(void) = ^{printf("val=%d\n",val);};  
val = 2;  
blk(); 

 

在Block定義時即是將局部變量的值傳給Block變量所指向的結構體,所以在調用Block以前對局部變量進行修改並不會影響Block內部的值,同時內部的值也是不可修改的網絡

在局部變量前使用__block修飾,在Block定義時即是將局部變量的指針傳給Block變量所指向的結構體,所以在調用Block以前對局部變量進行修改會影響Block內部的值,同時內部的值也是能夠修改的
函數

全局變量所佔用的內存只有一份,供全部函數共同調用,在Block定義時並未將全局變量的值或者指針傳給Block變量所指向的結構體,所以在調用Block以前對局部變量進行修改會影響Block內部的值,同時內部的值也是能夠修改的學習

在Block定義時即是將靜態變量的指針傳給Block變量所指向的結構體,所以在調用Block以前對靜態變量進行修改會影響Block內部的值,同時內部的值也是能夠修改的
動畫

在ARC默認狀況下,Block的內存存儲在堆中,ARC會自動進行內存管理,程序員只須要避免循環引用便可ui

 

 

block的語法格式

    //有返回值有蠶食的block
  NSString * (^testBlock)(NSString *) = ^NSString * (NSString * name){ NSLog(@"%@",name); return name; }; testBlock(@"cc"); //沒有返回值的block void (^testBlock)(NSString *) = ^(NSString * name){ NSLog(@"%@",name); }; testBlock(@"cc"); //沒有返回值也沒有參數的block void (^testBlock)(void) = ^{ NSLog(@"nonono"); }; testBlock();

 

typedef簡化Block的聲明

     使用typedef簡化block聲明,而後把block看成方法的參數atom

     在使用方法的時候傳入一個定義好的blockurl

     在方法執行的時候就會執行這個block

typedef void (^blockName)(NSString * name);
[self blockDefine:^(NSString *name) {
     NSLog(@"%@",name);
            
}];
-(void)blockDefine:(blockName)b{
//其餘代碼 b(@"bb"); }

 

聲明一個block類型的屬性

//block屬性


//使用typedef定義以後再聲明成屬性@property (nonatomic, copy) void (^btnClickedBlock)(UIButton *sender);
typedef void(^ClickBlock)(NSInteger index);
@property (nonatomic, copy) ClickBlock imageClickBlock;

 

block的循環引用

 oc中,可能引發循環引用的狀況有三種:block,delegate,NStimer

通常來講咱們總會在設置Block以後,在合適的時間回調Block,而不但願回調Block的時候Block已經被釋放了,因此咱們須要對Block進行copy,copy到堆中,以便後用。

Block可能會致使循環引用問題,由於block在拷貝到堆上的時候,會retain其引用的外部變量,若是對象內部有一個Block屬性,而在Block內部又訪問了該對象,那麼會形成循環引用

- (void) dealloc {
    NSLog(@"no cycle retain");
} 

- (id) init {
    self = [super init];
    if (self) {

        #if TestCycleRetainCase1
        //會循環引用
        self.myblock = ^{
            [self doSomething];
        };
  
        #elif TestCycleRetainCase2
        //會循環引用
        __block TestCycleRetain * weakSelf = self;
        self.myblock = ^{
            [weakSelf doSomething];
        };

        #elif TestCycleRetainCase3
        //不會循環引用
        __weak TestCycleRetain * weakSelf = self;
        self.myblock = ^{
            [weakSelf doSomething];
        };

        #elif TestCycleRetainCase4
        //不會循環引用
        __unsafe_unretained TestCycleRetain * weakSelf = self;
        self.myblock = ^{
            [weakSelf doSomething];
        };

        #endif NSLog(@"myblock is %@", self.myblock);
    }
    return self;
}
  • MRC狀況下,用__block能夠消除循環引用。
  • ARC狀況下,必須用弱引用才能夠解決循環引用問題,iOS 5以後能夠直接使用__weak,以前則只能使用__unsafe_unretained了,__unsafe_unretained缺點是指針釋放後本身不會置

在上述使用 block中,雖然說使用__weak,可是此處會有一個隱患,你不知道 self 何時會被釋放,爲了保證在block內不會被釋放,咱們添加__strong。更多的時候須要配合strongSelf使用,以下:

__weak __typeof(self) weakSelf = self; 
self.testBlock =  ^{
       __strong __typeof(weakSelf) strongSelf = weakSelf;
       [strongSelf test]; 
});

 

可是並非全部的地方都要用到weakself,當self不持有,也不間接持有這個block的時候,就不須要使用weakself,好比
//使用coreanimation的時候不須要
[UIView animateWithDuration:0.5 animations:^{ NSLog(@"%@", self); }];
//使用Masonry的時候也不須要weakself [self.headView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.otherView.mas_centerY); }];

 

 
 

 

 

 

 

 

 

 block的經典案例:

給UIView封裝手勢觸發方法

UIView+AddClickedEvent.m


- (void)addClickedBlock:(void(^)(id obj))clickedAction{ self.clickedAction = clickedAction; // :先判斷當前是否有交互事件,若是沒有的話。。。全部gesture的交互事件都會被添加進gestureRecognizers中 if (![self gestureRecognizers]) { self.userInteractionEnabled = YES; // :添加單擊事件 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)]; [self addGestureRecognizer:tap]; } } - (void)tap{ if (self.clickedAction) { self.clickedAction(self); } }

 點擊cell中的按鈕觸發vc中的block方法

//cell中的代碼
//Block
@property (nonatomic, copy) void (^btnClickedBlock)(void);
// 點擊方法
- (IBAction)btnClickedAction:(UIButton *)sender {
    if (self.btnClickedBlock) {
        self.btnClickedBlock();
    }
}

// vc中的代碼
cell.btnClickedBlock = ^{
    //刷新當前cell
    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
};

 對AFNetWorking進行二次封裝

+(void)quaryWithDic:(NSDictionary *)dic andUrlString:(NSString *)url :(void(^)(NSDictionary *))block{
    NSString * urlString = [NSString stringWithFormat:@"%@%@",SERVER,url];
    
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];;
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    [manager.requestSerializer setValue:@"1.0" forHTTPHeaderField:@"version"];
    [manager.requestSerializer setValue:@"ios" forHTTPHeaderField:@"terminal"];
    
    
    [manager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
    manager.requestSerializer.timeoutInterval = 10.0f;
    [manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
    
    
    [manager POST:urlString parameters:dic progress:^(NSProgress * _Nonnull uploadProgress) {
        
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        
        NSLog(@"%@ net request is %@",urlString,extracted(responseObject));
        block(responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        NSLog(@"the net request is failed ########################################## %@",error);
        block(@{@"code":@-1,@"message":@"網絡鏈接錯誤"});
        
    }];

}

 block的鏈式寫法

//1 在CaculateMaker.h文件中聲明一個方法add:
CaculateMaker.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface CaculateMaker : NSObject

@property (nonatomic, assign) CGFloat result;

- (CaculateMaker *(^)(CGFloat num))add;

@end


//2 在CaculateMaker.m文件中實現add方法:
CaculateMaker.m
#import "CaculateMaker.h"

@implementation CaculateMaker

- (CaculateMaker *(^)(CGFloat num))add;{
    return ^CaculateMaker *(CGFloat num){
        _result += num;
        return self;
    };
}

@end

//3.3.3 在viewController裏面導入CaculateMaker.h文件,而後調用add方法就完成了鏈式語法:
ViewController.m
CaculateMaker *maker = [[CaculateMaker alloc] init];
maker.add(20).add(30);

 

 

基本上是照着這個博客來學習的,這個博客寫的很是好,very 牛逼

https://www.jianshu.com/p/bcd494ba0e22 

 

這個博客寫的也很好,原理性方面寫的比較多 

https://www.jianshu.com/p/14efa33b3562

 

 這個是面試向,能夠參考

https://www.jianshu.com/p/4c652206a239

 

 

啊啊啊,好難過,已經六月14號了,頹廢了半個月我臥槽

冰期時代已經玩膩了,都沒啥好玩的了,若是不出新關卡就不想碰了
若是一年能夠攢20w就行了,五年就能攢100w了,等社保到期就能夠買一個小房子了嘿嘿嘿,房價應該比較穩定,慢慢漲的話還能接受

先找個18k的工做,而後有時間看看遊戲怎麼搞,我突然理解了唐巧巧的感受

 

我今天想起來,我不是由於王者榮耀很差玩纔不玩的,我是由於手機不行纔不玩的嚶嚶嚶

找到工做就換手機

垃圾小米

 

今天已經六月15號了,嗯嗯,日特碼哦,今天必定要雄起!!!

 

好吧,依然沒有雄起,今天是20號,今天必定要雄起!!!

 

好吧好吧,今天22號,今天不雄起了,今天雌起!

 

今天7月1號了哈哈哈,我如今很想死掉

今天7月4號了,個人心已經死了

 

 

今天玩遊戲的時候,遇到了一個特別喜歡說話的隊友,雖然感受有點逗比,跟個人節奏也不太同樣,可是輸出很高,因此我瞬間就不介意他處處夢遊了,加上另一個打上單的一塊兒,咱們三我的打了好幾局排位,每次都是碾壓對方,感受對面都是菜b的感受,太爽了,終於有一種玩遊戲的感受了,哈哈哈,這種遊戲果真仍是要有好隊友才玩的下去

相關文章
相關標籤/搜索