1. 程式人生 > >ReactiveCocoa 中 集合類RACSequence 和 RACTuple底層實現分析

ReactiveCocoa 中 集合類RACSequence 和 RACTuple底層實現分析

111194012-8f233f770f58594b

前言

在OOP的世界裡使用FRP的思想來程式設計,光有函式這種一等公民,還是無法滿足我們一些需求的。因此還是需要引用變數來完成各式各樣的類的操作行為。

在前幾篇文章中詳細的分析了RACStream中RACSignal的底層實現。RACStream還有另外一個子類,RACSequence,這個類是RAC專門為集合而設計的。這篇文章就專門分析一下RACSequence的底層實現。

目錄

  • 1.RACTuple底層實現分析
  • 2.RACSequence底層實現分析
  • 3.RACSequence操作實現分析
  • 4.RACSequence的一些擴充套件

一. RACTuple底層實現分析

在分析RACSequence之前,先來看看RACTuple的實現。RACTuple是ReactiveCocoa的元組類。

121194012-fd4ed6f45a960af0

1. RACTuple

123456789101112131415 @interfaceRACTuple:NSObject@property(nonatomic,readonly)NSUInteger count;@property(nonatomic,readonly)id first;@property(nonatomic,readonly)id second;@property(nonatomic,readonly)id third;@property(nonatomic,readonly)id fourth;@property
(nonatomic,readonly)id fifth;@property(nonatomic,readonly)id last;@property(nonatomic,strong)NSArray *backingArray;@property(nonatomic,copy,readonly)RACSequence *rac_sequence;// 這個是專門為sequence提供的一個擴充套件@end

RACTuple的定義看上去很簡單,底層實質就是一個NSArray,只不過封裝了一些方法。RACTuple繼承了NSCoding, NSCopying, NSFastEnumeration這三個協議。

1234567891011 -(id)initWithCoder:(NSCoder *)coder{self=[selfinit];if(self==nil)returnnil;self.backingArray=[coder decodeObjectForKey:@keypath(self.backingArray)];returnself;}-(void)encodeWithCoder:(NSCoder *)coder{if(self.backingArray!=nil)[coder encodeObject:self.backingArray forKey:@keypath(self.backingArray)];}

這裡是NSCoding協議。都是對內部的backingArray進行decodeObjectForKey:和encodeObject: 。

12 -(instancetype)copyWithZone:(NSZone *)zone{// we're immutable, bitches!    

上面這是NSCopying協議。由於內部是基於NSArray的,所以是immutable不可變的。

123 -(NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained[])buffer count:(NSUInteger)len{return[self.backingArray countByEnumeratingWithState:state objects:buffer count:len];}

上面是NSFastEnumeration協議,快速列舉也都是針對NSArray進行的操作。

123456789 // 三個類方法+(instancetype)tupleWithObjectsFromArray:(NSArray *)array;+(instancetype)tupleWithObjectsFromArray:(NSArray *)arrayconvertNullsToNils:(BOOL)convert;+(instancetype)tupleWithObjects:(id)object,...NS_REQUIRES_NIL_TERMINATION;-(id)objectAtIndex:(NSUInteger)index;-(NSArray *)allObjects;-(instancetype)tupleByAddingObject:(id)obj;

RACTuple的方法也不多,總共就6個方法,3個類方法,3個例項方法。

先看類方法:

12345678910111213141516171819 +(instancetype)tupleWithObjectsFromArray:(NSArray *)array{return[selftupleWithObjectsFromArray:arrayconvertNullsToNils:NO];}+(instancetype)tupleWithObjectsFromArray:(NSArray *)arrayconvertNullsToNils:(BOOL)convert{RACTuple *tuple=[[selfalloc]init];if(convert){NSMutableArray *newArray=[NSMutableArray arrayWithCapacity:array.count];for(id objectinarray){[newArray addObject:(object==NSNull.null?RACTupleNil.tupleNil:object)];}tuple.backingArray=newArray;}else{tuple.backingArray=[arraycopy];}returntuple;}

先看這兩個類方法,這兩個類方法的區別在於是否把NSNull轉換成RACTupleNil型別。根據入參array初始化RACTuple內部的NSArray。

131194012-0cbbbf49383bb05f

RACTuplePack( ) 和 RACTuplePack_( )這兩個巨集的實現也是呼叫了tupleWithObjectsFromArray:方法

12345 #define RACTuplePack(...) \RACTuplePack_(__VA_ARGS__)#define RACTuplePack_(...) \([RACTuple tupleWithObjectsFromArray:@[metamacro_foreach(RACTuplePack_object_or_ractuplenil,,__VA_ARGS__)]])

這裡需要注意的是RACTupleNil

123456789 +(RACTupleNil *)tupleNil{staticdispatch_once_t onceToken;staticRACTupleNil *tupleNil=nil;dispatch_once(&onceToken,^{tupleNil=[[selfalloc]init];});returntupleNil;}

RACTupleNil是一個單例。

重點需要解釋的是另外一種類方法:

123456789101112131415161718192021222324252627282930 +(instancetype)tupleWithObjects:(id)object,...{RACTuple *tuple=[[selfalloc]init];va_list args;va_start(args,object);NSUInteger count=0;for(id currentObject=object;currentObject!=nil;currentObject=va_arg(args,id)){++count;}va_end(args);if(count==0){tuple.backingArray=@[];returntuple;}NSMutableArray *objects=[[NSMutableArray alloc]initWithCapacity:count];va_start(args,object);for(id currentObject=object;currentObject!=nil;currentObject=va_arg(args,id)){[objects addObject:currentObject];}va_end(args);tuple.backingArray=objects;returntuple;}

這個類方法的引數是可變引數型別。由於用到了可變引數型別,所以就會用到va_list,va_start,va_arg,va_end。

123456789101112 #ifndef _VA_LIST_T#define _VA_LIST_Ttypedef__darwin_va_list va_list;#endif /* _VA_LIST_T */#ifndef _VA_LISTtypedef__builtin_va_list va_list;#define _VA_LIST#endif#define va_start(ap, param) __builtin_va_start(ap, param)#define va_end(ap)          __builtin_va_end(ap)#define va_arg(ap, type)    __builtin_va_arg(ap, type)
  1. va_list用於宣告一個變數,我們知道函式的可變引數列表其實就是一個字串,所以va_list才被宣告為字元型指標,這個型別用於宣告一個指向引數列表的字元型指標變數,例如:va_list ap;//ap:arguement pointer
  2. va_start(ap,v),它的第一個引數是指向可變引數字串的變數,第二個引數是可變引數函式的第一個引數,通常用於指定可變引數列表中引數的個數。
  3. va_arg(ap,t),它的第一個引數指向可變引數字串的變數,第二個引數是可變引數的型別。
  4. va_end(ap) 用於將存放可變引數字串的變數清空(賦值為NULL)。

剩下的3個例項方法都是對陣列的操作,沒有什麼難度。

一般使用用兩個巨集,RACTupleUnpack( ) 用來解包,RACTuplePack( ) 用來裝包。

1234567891011121314 RACTupleUnpack(NSString *string,NSNumber *num)=[RACTuple tupleWithObjects:@"foo",@5,nil];RACTupleUnpack(NSString *string,NSNumber *num)=RACTuplePack(@"foo",@(5));NSLog(@"string: %@",string);NSLog(@"num: %@",num);/* 上面的做法等價於下面的 */RACTuple *t=[RACTuple tupleWithObjects:@"foo",@5,nil];NSString *string=t[0];NSNumber *num=t[1];NSLog

相關推薦

ReactiveCocoa 集合RACSequence RACTuple底層實現分析

前言 在OOP的世界裡使用FRP的思想來程式設計,光有函式這種一等公民,還是無法滿足我們一些需求的。因此還是需要引用變數來完成各式各樣的類的操作行為。 在前幾篇文章中詳細的分析了RACStream中RACSignal的底層實現。RACStream還有另外一個子類,RACS

java物件鎖對比分析

      說到鎖機制,不得不提到Thread執行緒,而又不得不提到synchronized關鍵字,這個單詞的意思是表示“同步”的意思。用它去修飾方法函式的時候,如果有多個執行緒同時呼叫這個方法函式的時候,那麼當一個執行緒獲得鎖的時候,其他的執行緒只

Java集合set、Listmap的遍歷方式

Java中集合類的遍歷方式 Java中集合分為set、List和map。 1.set集合 set集合常用的有兩種遍歷方式: Set<String>  set = new HashSet<String>(); 第一種利用for迴圈: for(S

集合 Java集合解析一些有深入的面試題

第一題:       現有的程式程式碼模擬產生了16個日誌物件,並且需要執行16秒才能列印完這些日誌,請在程式中增加4個執行緒去呼叫parseLog()方法來分頭列印       這16個日誌物件,程式只需要執行4秒即可列印完這些日誌物件。 原始程式碼: pub

ReactiveCocoa RACSignal 冷訊號熱訊號底層實現分析

前言 關於ReactiveCocoa v2.5中冷訊號和熱訊號的文章中,最著名的就是美團的臧成威老師寫的3篇冷熱訊號的文章: 由於最近在寫關於RACSignal底層實現分析的文章,當然也逃不了關於冷熱訊號操作的分析。這篇文章打算分析分析如何從冷訊號轉成熱訊號的底層實現。

Java集合容器初步了解

equals treemap 輸入 strong 字符串數組 通過 system 結構 shm   容器(Collection)     數組是一種容器,集合也是一種容器     java編程中, 裝其他各種各樣的對象(引用類型)的一種東西, 叫容器     (圖書

12. 集合CollectionMap

sid 並且 當前 ria static indexof tran alt -i html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,addr

23.python屬性實例屬性

ash ron huang ant pass iou cli ict bin %E5%9C%A8myeclipse%E4%B8%AD%E4%BD%BF%E7%94%A8maven%E5%89%8D%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5

第十一課 集合CollectionMap

什麽是 基本數據類型 16px 開始 有序 面向對象 style 數據 取出 集合類 面向對象語言對事物的體現都是以對象的形式,所以為了方便對多個對象的操作,就對對象進行存儲,集合就是存儲對象最常用的方式。 數組和集合類都是容器,他們有什麽不同? 數組雖然也可以存儲對象,但

JS引用

另一個 bsp 引用類型 nbsp 對象 logs 包括 方式 console 一.值類型 例子: 1 var a=10; 2 var b=a; 3 a=20; 4 console.log(b); //10 例子中,將a的值賦給了b,b=10,然後改變a的值不會

ReactiveCocoa有關集合的使用

pro tsig 獲取 acs mod set instance 遍歷 end Sequences 集合 表示一個不可變的序列值且不能包含空值, 1.實現NSArray的快速遍歷 NSArray *numbers = @[@1, @2, @3, @4, @5, @6];

objc方法實例方法有什麽本質區別聯系

實例 屬於 通過 實例對象 對象方法 self 類方法 緩存 變量 類方法: 類方法是屬於類對象的 類方法只能通過類對象調用 類方法中的self是類對象 類方法可以調用其他的類方法 類方法中不能訪問成員變量 類方法中不能直接調用對象方法 類方法是存儲在元類對象的方法緩存

SSM-MyBatis-07:MybatisSqlSession的insertdelete底層到底做了什麽

src batis mit image updating obj color idea快捷鍵 手動 先點進去看一下insert方法 用ctrl加鼠標左鍵點進去看   發現是一個接口SqlSession的方法,沒有實現 ,但是通過裏氏替換原則的想法,他是接口接收了實現類,所

【cocos2dxNodegetParentgetChildByTag()】學習體會

mil 提高 cos cleanup HR -c ldr 12px 而不是 參考http://cn.cocos2d-x.org/doc/cocos2d-x-3.0/

在JavaScript引用型的區別

AC 存儲方式 說明 添加 asc TE num style src 一、存儲方式不一樣 基本數據類型 變量存儲的是簡單的數據段,存儲的是具體的值,是輕量級的數據存儲方式 引用類型 引用類型的值,可以由多個值構成的對象,引用類型的變量存儲的是對象引用地址。引用類型是重量的數

Python屬性物件屬性

作者:黎智煊 ,叩丁狼高階講師。本文為原創文章,轉載請註明出處。     在瞭解了類基本的東西之後,下面看一下python中這幾個概念的區別 先來談一下類屬性和例項屬性 在前面的例子中我們接觸到的就是例項屬性(物件屬性),顧名思義,類屬性就是類

Python方法靜態方法

作者:黎智煊 ,叩丁狼高階講師。本文為原創文章,轉載請註明出處。     類方法 是類物件所擁有的方法,需要用修飾器@classmethod來標識其為類方法,對於類方法,第一個引數必須是類物件,一般以cls作為第一個引數(當然可以用其他名稱的變數作

c++string物件字元陣列之間的相互轉換

string類在c++中是一個模板類,位於名字空間std中,注意這裡不是string.h,string.h是C字串標頭檔案。   將string型別轉換為字元陣列char arr[10];string s("ABCDEFG");int len = s.copy(arr,&nb

.集合Set,HashSet,TreeSet及其底層實現HashMap紅黑樹;Collection總結

ONE.Set集合 one.Set集合的特點  無序,唯一 TWO.HashSet集合 1.底層資料結構是雜湊表(是一個元素為連結串列的陣列) 2.那麼HashSet如何來實現元素的唯一性的呢? 通過一HashSet新增字串的案例檢視HashSet中add()的原始碼,

Python 變數例項變數(關鍵詞:Python/變數/例項變數)

類變數: class 語句的頂層進行賦值的變數,會被附加在類中,被所有例項所共享; 例項變數:附加在例項上的變數,不被共享,可通過這 2 種方式建立或修改: aInstance.name = sth 的形式; 類的例項方法中,self.name = sth 的形式。