源码

首页 » 归档 » 源码 » ReactNative源码条记——你知道几条?-ios学习从入门到精通尽在姬长信

ReactNative源码条记——你知道几条?-ios学习从入门到精通尽在姬长信

分享最热门的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。

用意志战胜身体的惰性!

(0)

本文由 姬長信 创作,文章地址:https://blog.isoyu.com/archives/727.html
采用知识共享署名4.0 国际许可协议进行许可。除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为:7月 15, 2016 at 11:59 上午

关键词:

热评文章

发表回复

[必填]

我是人?

提交后请等待三秒以免造成未提交成功和重复