日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ios 添加block 类别_iOS 关于Block代码块的详解

發布時間:2024/10/12 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ios 添加block 类别_iOS 关于Block代码块的详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

block

上圖就是一個block簡單使用,它包括了block的聲明、賦值實現、調用 三個部分,其中,實現部分可以看作是一種匿名函數;跟函數一樣,block也是需要調用才能執行內部代碼的;賦值的行為又讓block看起來跟數據類型類似

代碼塊Block是在iOS4開始引入的,是對C語言的擴展,用來實現匿名函數的特性

Block是一種特殊的數據類型,可以像基本數據類型一樣定義成變量、作為參數、返回值來使用

Block還可以保存一段代碼,在需要的時候調用

在iOS開發中,Block被系統應在很多地方,例如:GCD、UIView動畫、排序等,我們開發者也可以應用在各類回調、傳值、傳消息等

Block的聲明、賦值實現、調用

Block的聲明樣式。

返回類型 (^Block名稱)(參數列表)

void(^myBlock)(NSString *, NSString *)

Block的返回類型分為有返回類型和無返回類型(void),參數列表也可有也可以沒有,具體看需求

// 無返回類型無參數列表

void(^block)();

// 無返回類型有參數列表

void(^block)(int);

// 有返回類型無參數列表

int(^block)();

// 有返回列表有參數列表

int(^block)(int);

Block的簡單使用:聲明、賦值、調用

Block變量的賦值格式為:

Block變量 = ^(參數列表){函數體}; // 這里的參數列表一定要和聲明時的參數列表一致

// 聲明

void(^block)();

// 賦值

block = ^(){

NSLog(@"Hello World");

};

// 調用

block();

也可以在聲明時完成賦值

// 聲明、賦值

void(^block)() = ^(){

NSLog(@"Hello World");

};

// 調用

block();

定義Block類型

前面提到過,Block是一種特殊的數據類型,我們可以使用 typedef 來定義 Block 類型,這樣我們就可以使用該類型來聲明很多相同的Block變量了。

typedef 返回類型(^Block名稱)(參數列表);

示例:

// 聲明一個Block類型

typedef void(^Block)();

// 使用定義兩個block變量

Block myBlock,myNewBlock;

// 賦值實現

myBlock = ^(){

NSLog(@"Hello World");

};

myNewBlock = ^(){

NSLog(@"Hello World, I am lolita0164.");

};

// 調用

myBlock();

myNewBlock();

ARC模式下簡單應用

作為對象屬性實現消息傳遞

前面說到,Block保存一段代碼,在需要的時候調用。我們可以將使用Block的三個步驟拆開,實現消息傳遞、傳值功能。

// 定義Block類型

typedef void(^Block)(NSString *);

@interface Person : NSObject

// 聲明Block變量

@property (nonatomic, copy) Block myBlock;

-(void)sayHello;

@end

@implementation Person

-(void)sayHello{

// Block調用

self.myBlock(@"Hello, I am lolita0164");

}

@end

在定義聲明、調用之后,還缺少實現的部分,這一步通常由外部實現。

Person *p = [Person new];

// Block賦值實現

p.myBlock = ^(NSString *string) {

NSLog(@"%@",string);

};

[p sayHello];

這樣,我們就可以在Block的賦值實現部分里拿到 p類里的數據了。

作為函數參數實現數據回調

我們將之前的例子稍加改動

// 定義Block類型

typedef void(^Block)(NSString *);

@interface Person : NSObject

// 將Block作為參數

-(void)sayHelloUseBlock:(Block)myBlock;

@end

@implementation Person

-(void)sayHelloUseBlock:(Block)myBlock{

// Block調用

myBlock(@"Hello, I am lolita0164");

}

@end

在外部進行實現。

Person *p = [Person new];

// Block實現

[p sayHelloUseBlock:^(NSString *string) {

NSLog(@"%@",string);

}];

作為參數和作為屬性傳遞消息,在應用場景稍稍有些不同。

作為參數時,通常和當前的方法有著緊密的聯系,函數體內部需要與調用的外部進行交互。例如在請求方法中,經常會使用到block進行回調,而這個block和當前的方法關系緊密,通常是該方法的結果回調。又或者是方法執行期間需要外部提供一定的信息,從而通過block獲取外部提供的數據。

作為屬性時,通常是和當前類相關,作為類與類之間的交互代表。

作為返回值實現鏈式語法

將block作為返回值的經典例子就是約束庫 masonry,這個庫在做完每次約束設置之后通過 block 將實例再次回調,就形成了鏈式語法。

[view makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(view1.mas_right).offset(10);

make.top.equalTo(view1).offset(0);

make.right.equalTo(-10);

make.size.equalTo(viewWidth);

}];

下面通過創建顏色類來演示 block 作為參數的使用。

// block 作為返回值

+(UIColor* (^)(CGFloat, CGFloat, CGFloat))rgb{

// block 的聲明和實現

UIColor* (^rgbBlock)(CGFloat, CGFloat, CGFloat) = ^id(CGFloat r, CGFloat g, CGFloat b) {

return [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:1];

};

return rgbBlock;

}

解析

返回值是一個有返回值參數有三個的block:UIColor * (^)(CGFloat, CGFloat, CGFloat)。我們在該方法的內部進行了block的聲明和具體實現,并且將其作為返回值返回了出去,那么外部在調用該方法之后接收到的是一個block,可以使用該值。

那么外部使用情況如下。

// 接收 block 類型

UIColor* (^colorBlock)(CGFloat, CGFloat, CGFloat) = [UIColor rgb];

// 使用 block 獲取到顏色

UIColor* color = colorBlock(10,33,65);

self.view.backgroundColor = color;

在丟棄不需要的部分后,代碼如下。

+(UIColor* (^)(CGFloat, CGFloat, CGFloat))rgb{

return ^id(CGFloat r, CGFloat g, CGFloat b) {

return [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:1];

};

}

// 使用block作為參數的方法

self.view.backgroundColor = UIColor.rgb(10, 33, 65);

Block 和 變量

Block訪問局部變量問題

block 內部可以訪問局部變量。

int global = 100;

void (^Block)() = ^(){

NSLog(@"global = %i", global);

};

Block(); // 輸出 "global = 100"

但是 block 會把變量 復制 為自己私有的const變量,也就是說block會捕獲棧上的變量(或指針),將其復制為自己私有的const變量,當變量被修改時,不會影響到block自己私有的const變量。

int global = 100;

void (^Block)() = ^(){

NSLog(@"global = %i", global);

};

global = 101;

Block(); // 輸出 "global = 100"

在Block中不可以直接修改局部變量。

int global = 100;

void (^Block)() = ^(){

global ++; // 這句報錯

NSLog(@"global = %i", global);

};

Block();

但是可以通過 __block 修飾符修改局部變量。

__block int global = 100;

void (^Block)() = ^(){

NSLog(@"global = %i", global);

};

global = 101;

Block(); //輸出 "global = 101"

__block int global = 100;

void (^Block)() = ^(){

global ++; // 這句正確

NSLog(@"global = %i", global);

};

Block(); //輸出 "global = 101"

原因:在局部變量前使用 __block修飾 ,在Block定義時便是將局部變量的指針傳給Block變量所指向的結構體,因此在調用Block之前對局部變量進行修改會影響Block內部的值,同時內部的值也是可以修改的。

Block訪問全局變量、靜態變量問題

可以訪問和修改。

全局變量所占用的內存只有一份,供所有函數共同調用,在Block定義時并未將全局變量的值或者指針傳給Block變量所指向的結構體,因此在調用Block之前對全局變量進行修改會影響Block內部的值,同時內部的值也是可以修改的。

在Block定義時便是將靜態變量的指針傳給Block變量所指向的結構體,因此在調用Block之前對靜態變量進行修改會影響Block內部的值,同時內部的值也是可以修改的。

ARC下的內存管理

在ARC默認情況下,Block的內存存儲在堆中,ARC會自動進行內存管理,我們只需要避免循環引用即可。

// 當Block變量出了作用域,Block的內存會被自動釋放

void(^myBlock)() = ^{

NSLog(@"------");

};

myBlock();

如果在Block中引用了外面的對象,會對所引用的對象進行強引用,但是在Block被釋放時會自動去掉對該對象的強引用,因此比并不會造成內存泄漏問題。

Person *p = [[Person alloc] init];

void(^myBlock)() = ^{

NSLog(@"------%@", p);

};

myBlock();

// Person對象在這里可以正常被釋放

// 注:這里的Block只是單方面的強引用,所以不會產生循環引用,也不會內存泄漏

如果對象內部引用一個Block屬性,而在Block內部又訪問了該對象,那么會造成循環引用,導致內存泄漏。

self.block = ^{

NSLog(@"------%@", self);

};

解決辦法:使用一個弱引用的指針指向該對象,然后在Block內部使用該弱引用指針來進行操作,這樣就避免了Block對對象進行強引用。

__weak typeof(self) weakSelf = self;

weakSelf.block = ^{

NSLog(@"------%@", weakSelf);

};

提示:如果只是Block單方面地對外部變量進行強引用,并不會造成內存泄漏。

補充

1、聲明block屬性的時候為什么用copy呢?

在說明為什么要用copy前,先思考下block是存儲在棧區還是堆區呢?其實block有3種類型:

全局塊(_NSConcreteGlobalBlock)

棧塊(_NSConcreteStackBlock)

堆塊(_NSConcreteMallocBlock)

全局塊存儲在靜態區(也叫全局區),相當于OC中的單例;棧塊存儲在棧區,超出作用域則馬上被銷毀。堆塊存儲在堆區中,是一個帶引用計數的對象,需要自行管理其內存。

關于內存分配,請看這篇:C語言內存分配。

怎么判斷一個block所在的存儲位置呢?

block不訪問外界變量(包括棧中和堆中的變量)

block既不在棧中也不在堆中,此時就為全局塊,ARC和MRC下都是如此。

block訪問外面變量

MRC環境下:默認存儲在棧區

ARC環境下:默認存儲在堆中,實際上是先放在棧區,在ARC情況下自動又拷貝到堆區,自動釋放

因此,使用 copy 修飾符的作用就是將block從棧區拷貝到堆區

為什么要這么做呢?官方給出的答案是:

復制到堆區的主要目的就是 保存 block 的狀態,延長其聲明周期。因為block如果在棧上的話,其所屬的變量作用域結束,該block就被釋放掉了,block中的 __block 變量也同時被釋放掉了,為了解決超出作用域就被釋放的問題,我們就需要把block復制到堆中。

總結

OC 中的 block 是對 C 語言的匿名函數的一種特性是實現。block 具有函數特性,同時也可以作為變量使用。block 可以作為屬性、參數、返回值使用。想要在 Block 內部修改外部變量時,需要使用 __Block 將變量指針傳遞給 block。在使用 Block 時需要特別注意內存泄漏的問題。

總結

以上是生活随笔為你收集整理的ios 添加block 类别_iOS 关于Block代码块的详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产一区二区三区免费在线观看 | 欧美黑人精品一区二区 | 日韩黄色免费网站 | av在线天天 | 久久爱成人 | 亚洲男人天堂网站 | jizzjizz在线播放 | 色婷婷一区二区三区 | 国产精品久久影院 | 91精品国产一区 | 色香蕉影院 | 亚洲涩视频 | 国产精品嫩草影院精东 | 91成人免费看片 | 四虎影视在线播放 | 狠狠cao日日穞夜夜穞av | 日韩区在线 | 一本色道久久综合精品婷婷 | 我要操婊 | 色呦呦免费观看 | 性感美女高潮 | 国产xxxxx在线观看 | 欧美日韩一区二区三区在线 | 麻豆视频入口 | 久久久久久久久综合 | 国产视频一 | 69视频在线观看免费 | 成人亚洲免费 | 日韩夜夜高潮夜夜爽无码 | jizzjizzjizz亚洲| 天天干天天谢 | 少妇性l交大片免潘金莲 | 深夜福利国产 | 亚洲黄色影院 | 欧美一区在线看 | 欧美a视频在线观看 | ass日本粉嫩pics珍品 | 狠狠五月| 波多野结衣高清视频 | 一区二区三区在线观 | 黄色天堂网站 | 光棍影院手机版在线观看免费 | 久操精品视频 | 中文二区 | 免费裸体视频网站 | 国产三区在线播放 | 色悠悠在线视频 | 一本色道久久综合亚洲精品小说 | 午夜久久精品 | 日韩亚洲一区二区 | 午夜精品小视频 | 国产精品传媒麻豆hd | 亚洲青涩| 三点尽露的大尺度国产 | 亚洲福利精品视频 | 亚洲国产精品成人综合色在线婷婷 | 精品人妻少妇一区二区 | 成人亚洲玉足脚交系列 | 久久综合综合久久 | 免费观看成年人网站 | 免费福利视频在线观看 | 午夜视频免费在线 | 欧美一区二区三区在线看 | 日本美女动态图 | 免费一级片网址 | www.黄色网 | 日韩特级黄色片 | 森林影视官网在线观看 | 国产精品一区二区在线免费观看 | 欧美日韩在线二区 | a免费观看 | 亚洲综合在线播放 | 特级西西人体444www | 91视频专区| 亚洲中字| 韩国黄色精品 | 91视频最新地址 | 亚洲精品中字 | 91免费观看网站 | 免费看裸体网站视频 | 狠狠躁日日躁夜夜躁av | 午夜成人影视 | 国产成人av网站 | 国产精品揄拍一区二区 | 欧美精品免费视频 | 欧美日韩精品亚洲精品 | 香蕉视频黄在线观看 | 欧美男同又粗又长又大 | 午夜片在线观看 | 都市激情校园春色亚洲 | 先锋影视av | 日本捏奶吃奶的视频 | 91麻豆精品一二三区在线 | 中文字幕日韩在线视频 | 成年人视频在线播放 | 国产精品亚洲无码 | 99久久精品无免国产免费 | 欧美黄页 | 亚洲国产精品自拍 |