国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > iOS > 正文

iOS 代理和block的理解

2019-11-09 18:42:09
字體:
來源:轉載
供稿:網友
首先兩者作用是一樣的,都是進行單一回調。不通的是,delegate是個對象,然后用過一個對象自己調用代理協議函數來完成整個流程。block是傳遞一個函數指針,利用函數指針執行來進行回調。還有在內存管理上需要注意,delegate不需要保存引用。block對引用數據有copy的處理。

1.block類型-存儲代碼塊的類型

在異步編程時常需要進行函數回調,在C#中會用匿名委托或者lambda表達式講一個操作作為參數進行傳遞.ObjC中是使用對于閉包的實現,在塊狀中我們可以持有或引用局部變量. 同時利用Block可以將一個操作作為參數進行傳遞;

blcok用法:

定義:返回值類型 ( ^變量名 ) ( 形參類型 );賦值:變量名=^(形參){代碼塊+形參變量};使用:變量(實參); 

例: 

int (^myBlcok)(int ,int)=^(int m,int n){ return m+n; }; //無參數時大括號前()可省略 myBlock(10,5); //調用塊,省略了接受塊返回值;

總結:經過簡單了解C與OC;發現從最小的一個變量到表達式再到一個函數,其實只起兩點作用: 值(返回值) 與 功能(行為,方法,作用).所以說一行代碼,按它是使用了值 還是 功能來解讀比較容易理解. 

Block做使用場景:

如果回調方法比較少,1~2,最好不要超過3個,這個時候使用block比較合適如果回調方法非常多,同時又不用每一個方法都必須實現,這個時候用delegate會比較方便!

block傳值的循環引用問題:

只有當block直接或間接的被self持有時,在block使用self時才需要替換為weak self。如果在 Block 內需要多次 訪問 self,則需要使用 strongSelf。

__weak __typeof__(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ __strong __typeof(self) strongSelf = weakSelf; [strongSelf doSomething]; [strongSelf doOtherThing]; });

typedef block格式

類似函數指針,直接在定義格式之前加 typedef關鍵字,之后變量名就是類型的別名了.typedef viod (^別名)(形參);一般以后需要使用block作為函數方法的參數時,為方便最好用別名.而在block作用返回值時,一定需要別名,因為編譯器不能識別做此時類型做何種解釋.延伸:經過測試,block在編譯時按代碼順序,而運行時按調用順序(變量作用域)

使用例子:KCButton.h

#import <Foundation/Foundation.h>@class KCButton;typedef void(^KCButtonClick)(KCButton *);@interface KCButton : NSObject#pragma mark - 屬性@property (nonatomic,copy) KCButtonClick onClick;#pragma mark 點擊方法-(void)click;@end

KCButton.m

#import "KCButton.h"@implementation KCButton-(void)click{ NSLog(@"Invoke KCButton's click method."); if (_onClick) { _onClick(self); }}@end

main.m

KCButton *button=[[KCButton alloc]init]; button.onClick=^(KCButton *btn){ NSLog(@"Invoke onClick method.The button is:%@.",btn); }; [button click]; /*結果: Invoke KCButton's click method. Invoke onClick method.The button is:<KCButton: 0x1006011f0>. */

block訪問外部變量

block內部可以訪問外部局部變量,但是此時是const copy方式,地址不同,相當于值傳遞,只讀的.如果外部定義時加前綴__block時,內部可改變外部局變值.block內部如果創建了和外部同名的變量,會屏蔽外部作用域.此時內部的變量也存在棧區;原因:block本質是代碼塊,ARC下創建的時候在堆區,此時代碼只是單純儲存,沒有功能;當調用的時候,相當于代碼增加到main中,這樣代碼塊中創建的變量就跟正常的一樣; (block調用完成內部變量即釋放,而堆區的只在釋放block時一起釋放).如果是靜態變量(static修飾局變,生命周期延長,存儲在數據區(同初始化的全局))和全局變量.地址傳遞.此時block存儲在全局區.常量字符串@"abc",加__block會引用常量變量(如:a變量,a = @"abc",內部可以任意修改a 指向的內容)的地址。不加block就是@"abc"本身地址,不可變;

三種類型block

根據block在內存中的位置"NSGlobaBlock"類似函數,存于代碼區--全局block"NNStackBlock"棧區,函數返回后的Block--棧"NSMallocBlock"堆block--堆block內沒有使用外部變量或是只使用了全局/靜態變量時.存于全局代碼區,為全局block;---(ARC和MRC下一致)當使用外部變量時MRC下,block代碼存于棧區;如果此外部變量A存于棧區,那么A會被copy到block分配的棧區;如果A是存于堆區,那么A在block塊內與快外相同.ARC下,block代碼存于堆區.如果此外部變量A存于棧區,那么A會被copy到block分配的堆區;如果A是存于堆區,那么A在block塊內與快外相同.如果需要修改外部變量,需要在變量前面聲明__Block;當使用下劃線Block修飾外部變量時:MRC下,無論變量A存于棧還是堆區,A在block塊內與快外相同;ARC下,如果此外部變量A存于棧區,那么A會被轉移而不是復制到堆區;如果A是存于堆區,那么A在block塊內與快外相同.

面試題:block的@property參數(內存管理參數)為什么要用copy:如果不用copy,此時不論ARC還是MRC都是棧Bolck,棧block會提前釋放,導致無法繼續使用;可以copy到堆區手動管理內存.(而字符串copy是防止字符串如果是非常量的,外部可變,造成非預估的結果;)

block在MRC下得內存隱患(NNStacKBlock)

Block_copy將block及內部變量拷貝到堆區.使用完畢用Blok_release(block變量)釋放此堆區空間;


block使用技巧

block結構快速顯示:inlineBlock...(也可右下角自定義快速顯示其他格式)Block作為方法參數時,最好把參數列表部分加上,這樣后面調用方法時,會自動有格式;做方法參數時,需要加上返回值類型;做返回值時,先定義別名,最后別忘記執行返回值;方法中,void(^)()表示block類型同int,做參和返回值;做實例變量@property (nonatomic, copy) void(^變量名)()get點語法獲取block類型實例變量時,自動執行,后面需加();

2.protocl協議的概念及使用

在ObjC中使用@protocol定義一組方法規范. 實現此協議的類 也必須實現對應的方法. 面向對象的語言接口本身是對象行為描述的 協議規范, 也就是說ObjC中@protocol和其他語言的接口定義是類似的, 只是ObjC的@interface關鍵字已經用于定義類了, 因此不會像C# 和java中那樣使用interface來定義接口;

1.定義:

只聲明而不實現方法 ,而讓遵守此協議的類實現協議聲明的方法;在.h 中

@protocol 協議名 <系統協議>,<其他協議2>... //方法聲明列表 @end
2.類遵守協議:

類聲明文件中:

@interface 類名:父類<協議1,協議2>@end
3.實現協議:

只需在此類的.m文件中實現協議聲明方法即可(根據協議定義時@option的關鍵字,有些必須實現,有些選擇實現);

4.應用:
協議只聲明多個方法,不實現, 不能定義屬性;只要遵守協議,就可以擁有協議的所有方法聲明;一個類遵守協議而實現的方法,聲明和實現都會遺傳給子類,而沒有實現的方法聲明會遺傳給子類,即協議可以 繼承 ;協議和類可以多對多,而一個協議又可以繼承其他一個或多個協議.所有協議默認遵守NSObject的基協議,其中聲明了很多基本方法.協議中有兩個關鍵字:@required(默認)必須實現的. @optional 選擇實現;作用域類似@public等關鍵字作用域

兩大作用

1. 做類型限制:程序員間交流

格式:id<協議名>obj;//表明 如果要給obj賦值,則賦值的對象必須遵守"協議"才可以賦值.不滿足會有警告;即id<協議名> obj=[類1 new],必須類1要遵守此協議;id 可換成類名,記得加*;引申的,在對象做實例變量時也可限制,例:@prperty Dog<協議> *dog

2.代理設計模式使兩個不同意義的事物分離解耦.一種常見編程思想:有些事自己不好做,找代理做;傳入的對象,代替當前類完成摸個功能;原理:對象關聯關系的類型限制(A對象擁有遵守特定協議的對象B)白手套作為主子的實例變量;應用場合:

當A發生了一些行為(ˇ?ˇ) 想~告訴B或B想監聽對象A的一些行為 A無法處理某些行為的時候,讓B幫忙;

思路:

先定義一個協議.定義代理類,遵守此協議.主類定義限定此協議類型的屬性.主類中要有行為 來觸發代理.

設置代理.

用父類還是id<協議>

不使用父類的原因:如果抽象一個父類的話, 還是有局限性, 因為很多時候, 不同類是無法抽象出共同的父類的. , 不能多繼承

3.Category

作用:在不修改原類的情況下擴展其他功能目的:對類方法進行歸類,便于分模塊開發大型類,團隊協作.聲明:@interface 類名(分類名)實現:@implementation 類名使用原類直接調用

注意:1)分類不能擴展任何新的實例變量; 

2)分類可以訪問原類的成員變量;(相當于原類方法調用) 3)如果分類中存在和原類同名方法,優先使用分類(功能更新); 4)如果多個分類都有同名方法,調用最后一個參與編譯的分類同名方法;在Compile Sources 文件編譯可以看到的的順序; 
分類的非正式協議:(面試題)

就是NSObject(和系統類框架)的類別(分類)即系統類的分類,增加了所有類的功能;類別接口中指定的方法可能會或者可能不會被框架類實際地實現,而是被子類重寫. 

分類的延展(匿名分類)Extendsion

延展是分類一個特例,匿名.且新添加的方法一樣要予以實現

@interface MyClass () { float value; //可以新增實例變量 }-(void)setValue:(float)newValue;@end

使用:

可以在原類.h直接聲明,原類.m中實現;不需要自己的.m文件;主要用于新增類的私有方法和私有變量.()
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 肇州县| 鄂托克前旗| 河源市| 普兰店市| 沧源| 固安县| 朝阳县| 望江县| 嘉定区| 八宿县| 印江| 信丰县| 金门县| 嫩江县| 达尔| 南乐县| 鞍山市| 梅州市| 都安| 原阳县| 东乡县| 同德县| 顺义区| 定南县| 兴山县| 商城县| 浪卡子县| 德昌县| 定边县| 奉节县| 威海市| 建昌县| 汝南县| 冷水江市| 吉首市| 永春县| 镇赉县| 广宗县| 宁武县| 黄大仙区| 两当县|