你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> ReactNative源碼筆記——你知道幾條?

ReactNative源碼筆記——你知道幾條?

編輯:IOS開發基礎

QQ截圖20160715105723600.jpg

投稿文章,作者:龐海礁(博客)

ReactNative是Facebook開源的一種實現移動跨平台開發的解決方案,目前在業界得到廣泛應用,這裡有非常詳細的中文使用指南。本文主要分享RN源碼中一些值得大家學習或者借鑒的代碼或者編寫技巧等,供大家學習參考。

整個RN庫包含10多個工程,有興趣的童鞋可以下載源碼查看具體細節,在此不再展開。

rnproject.png

宏定義巧用

整個ReactNative源碼工程中用到了大量的宏定義,包括RCT_EXTERN、RCT_NOT_IMPLEMENTED、RCT_EXPORT_METHOD以及RCT_EXPORT_MODULE等申明宏或者功能宏。通過宏定義的方式,可以非常方便嵌入功能代碼或者邏輯實現,重用代碼的同時又保持了代碼的整潔性

比如,ProtocolKit工程中,作者通過宏定義@defs將Protocol接口巧妙的實現在.h文件中,代碼簡介明了,又不失功能完整性。當然,RN工程中,RCT_NOT_IMPLEMENTED宏也有相似作用,實際項目中各位也可以嘗試通過宏定義實現一些常用功能模塊

關於iOS宏定義的文章有很多,在此推薦兩篇非常不錯的文章:RAC中必須要知道的宏、iOS宏的使用和技巧。

環境變量

iOS開發中,各位對#ifdef DEBUG應該非常熟悉,通過判斷該條件,可以區別當前運行環境是Debug環境還是Release環境。比如Release環境下通過重定義NSLog以屏蔽所有日志輸出

#ifdef DEBUG  
#define NSLog(...) NSLog(__VA_ARGS__)  
#else  
#define NSLog(...) {}  
#endif

進一步,是否可以考慮只在聯機調試環境下輸出日志?此時就涉及聯機調試環境的判斷,環境變量正好可以解決該問題

1468551113633426.png

Xcode可以在不同環境下自定義環境變量Environment Variables,通過在運行環境Run中自定義變量CI_USE_PACKAGER,此時便可在項目代碼中通過getenv()函數判斷當前運行環境

if (getenv("CI_USE_PACKAGER")) {  
    // to do...
}

被忽略的硬鍵盤

相較於軟鍵盤文字符號的輸入,對於APP來說,硬鍵盤的應用開發似乎很容易被忽視,畢竟,通常情況下,硬鍵盤輸入只會出現在模擬器環境下。

iOS7以後,系統定義有硬鍵盤響應交互類UIKeyCommand,通過UIKeyCommand,APP能夠監聽硬鍵盤的特定輸入響應,比如Command+D等,當然,前提是APP需要首先監聽該輸入命令。

UIKeyCommand的使用非常簡單,當需要在特定場景觸發某一事件,但又不想影響界面顯示的時候,不妨試試UIKeyCommand,具體使用可以看看這篇文章。

_cmd

iOS官方文檔中,_cmd表示當前方法的selector,你可以通過下面代碼打印輸出當前函數名

NSLog(@"Current method: %@", NSStringFromSelector(_cmd));

當然,實際項目中,你也可以這樣使用

NSNumber *rootTag = objc_getAssociatedObject(self, _cmd) ?: @1;
objc_setAssociatedObject(self, _cmd, @(rootTag.integerValue + 10), OBJC_ASSOCIATION_RETAIN_NONATOMIC);

瞧,是不是有點意思!

kCFNull

相對於nil NSNull而言,kCFNull筆者接觸較少,kCFNull可以理解為NSNull單例對象

id null1 = (id)kCFNull;
id null2 = [NSNull null];

打印地址

null1=(NSNull *)0x10426eaf0
null2=(NSNull *)0x10426eaf0

從上面測試結果可以看出它們其實指向同一地址, 可以簡單理解為 kCFNull === [NSNull null]

文本陰影NSShadow

APP開發中,程序猿可能經常需要在圖片或視頻上顯示文字,由於背景顏色跟文字顏色相近,導致文字看不清,比如時下火熱的直播彈幕顯示,為了確保文字顯示清晰,開發者一般會配上陰影或者文字描邊

給文本添加陰影描邊,系統提供有NSShadow類,可以這樣使用

NSShadow *shadow = [NSShadow new];
shadow.shadowOffset = CGSizeZero;
shadow.shadowBlurRadius = 5.0f;
shadow.shadowColor = [UIColor colorWithWhite:0.0f alpha:0.3f];
NSAttributedString *attString = [[NSAttributedString alloc] initWithString:@"www.olinone.com" 
                  attributes:@{NSShadowAttributeName: shadow, 
                                                                    NSForegroundColorAttributeName: [UIColor whiteColor]}];
lbl.attributedText = attString;

實際效果是這樣的,shadowBlurRadius值越小,文本描邊越清晰

1468551218698266.png

主線程判斷

判斷當前執行線程是否為主線程的方法有很多,比如

[NSThread isMainThread]
pthread_main_np

在RN中,它是這樣的

BOOL RCTIsMainQueue() {  
    static void *mainQueueKey = &mainQueueKey;  
    static dispatch_once_t onceToken;  
    dispatch_once(&onceToken, ^{    
        dispatch_queue_set_specific(dispatch_get_main_queue(), mainQueueKey, mainQueueKey, NULL);  
    });  
    return dispatch_get_specific(mainQueueKey) == mainQueueKey;
}

當然,由於無法查看NSThread內部實現機制,暫時無法了解孰優孰劣,不過,[NSThread isMainThread]貌似足矣!

volatile不簡單

在百科中,是這樣描述它的:就像大家更熟悉的const一樣,volatile是一個類型修飾符,它是被設計用來修飾被不同線程訪問和修改的變量。作為指令關鍵字,確保本條指令不會因編譯器的優化而省略,且要求每次直接讀值

簡單說,被volatile修飾的變量是多線程安全的,其次,不會因為編譯器優化導致讀值出錯。關於編譯器編譯優化可以看看這篇文章。

iOS開發中確保多線程安全的方法有很多,原子操作、線程鎖、單線程執行等等,本人也寫過相關文章iOS開發多線程同步。

在RN中,通過volatile修飾符,巧妙實現了多線程取消操作

__block volatile uint32_t cancelled = 0;
if (!cancelled) {   
    // to do...
}
OSAtomicOr32Barrier(1, &cancelled);

通過原子性操作訪問被volatile修飾的cancelled對象即可保障函數只執行一次。想想大家熟悉的單例dispatch_once_t,現在讓你設計單例對象,你又會如何設計了?

+ (instancetype)sharedInstance {  
    static RCTWebSocketManager *sharedInstance = nil;  
    static dispatch_once_t onceToken;  
    dispatch_once(&onceToken, ^{    
        sharedInstance = [self new];  
    });  
    return sharedInstance;
}

結構體Struct

說起Struct,不知各位對它印象如何?大學C課本中學過?NSObject類class原型貌似有講?

struct iOSDev {    
    NSString *nickName;
};

OC中一個簡單的結構體,在Swift中,Struct也可以這樣寫

struct iOSDev {    
    var nickName : String    
    func getBusinessCard() -> String {        
        return "(nickName),幽默的iOS開發者!"    
    }}; 
let iOSOlinone = iOSDev(nickName: "olinone")
print(iOSOlinone.getBusinessCard())

getBusinessCard為結構體函數,是不是感覺很方便!其實OC中也可以這樣寫

struct iOSDev {    
    NSString *nickName;    
    NSString *getBusinessCard() {        
    return [NSString stringWithFormat:@"%@,幽默的iOS開發者!", nickName];   
}}; 
iOSDev iosDev = iOSDev{@"olinone"};
NSLog(@"%@", iosDev.getBusinessCard());

當然,為Struct添加函數並不是C語言特性,而是C++特性,因此,為了編譯通過,你需要將.m文件修改成.mm文件。

Struct有其使用的特殊場景,相較於Class,合理的使用Struct可以使代碼更加整潔。同時,為了適應Swift中Struct強大特性,可以試著在OC項目中嘗試Struct。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved