React Native 源码笔记——你知道几条?
ReactNative是Facebook开源的一种实现移动跨平台开发的解决方案,目前在业界得到广泛应用,这里有非常详细的中文使用指南。本文主要分享RN源码中一些值得大家学习或者借鉴的代码或者编写技巧等,供大家学习参考。
整个RN库包含10多个工程,有兴趣的童鞋可以下载源码查看具体细节,在此不再展开。
宏定义巧用
整个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
进一步,是否可以考虑只在联机调试环境下输出日志?此时就涉及联机调试环境的判断,环境变量正好可以解决该问题:
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值越小,文本描边越清晰
主线程判断
判断当前执行线程是否为主线程的方法有很多,比如:
[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
最后,给大家来个段子吧:
话说一美女要在两个男人之间做选择,一个年纪大,长的丑,是个千万富翁,另一个年轻,帅气,iOS开发程序猿。 她对他们说,我会给你们一人一张纸条,写着我愿意的那张就是我的选择。 富翁打开纸条,看见上面写着我愿意,于是搂着她,坐上豪车高兴的走了。 年轻的小伙很伤心,打开纸条看见上面写着:“等我一个月~”
文章转载自 开源中国社区[http://www.oschina.net]
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
用jenkins搭建android自动打包环境
这里假设你已经搭建了jenkins的环境。否则,请阅读我的另一篇文章: http://my.oschina.net/u/930967/blog/298980 其实那个文章里面有用的就两句话的事儿,还是直接写在这里吧 jenkins是一个java web项目,可以去官网下载war包,放在tomcat的webapps下就能运行。 访问localhost:8080/jenkins进入 步入正题 任何一个开发工具,都提供了命令行工具。比如android用的是ant。java有maven。还有xcode,visual studio等等,都有对应的命令行工具。我们完全可以自己写一个shell脚本来完成打包的工作。 用命令打包adnroid项目 以下命令可以用来打包安卓项目,jenkins其实也是调用了类似的命令 ant build -f xxx/build.xml # build.xml文件的生成,可以参考http://913.iteye.com/blog/1995500 安装插件 jenkins支持多种插件,“联网”安装后即可使用,常见的有git插件,ant 插件,maven插件等。 在jenk...
- 下一篇
谷歌推车载系统 Android Auto 正式版即将上市
北京时间6月25日晚24时,谷歌I/O大会正式拉开大幕,谷歌宣布不久就将提供给开发者Android Auto的SDK开发工具,帮助开发者更好的开发汽车相关应用,并开放音频以及信息的API接口。 谷歌车载系统Android Auto,支持导航、交互以及音乐,而在中控显示的方式就像Google Now的卡片。车载系统的所有内容都来自手机,与汽车方向盘按钮兼容。 用户可以直接使用谷歌地图,并通过语音进行搜索及导航,与手机使用体验一致。当有新消息送达时,会自动语音播报,而用户也可以直接通过语音回复。 Android Auto与之前苹果的CarPlay最大不同在于,当安卓手机通过数据线连接到汽车之后,屏幕是投射到车里中控台显示屏的,显示风格与横版安卓界面没有太大不同,因此用户可以获得非常一致的操作体验,所有程序其实是运行在手机上的,而CarPlay的界面则是完全重新设计的。 Android Auto在全球拥有40家新合作伙伴,包括菲亚特、奥迪、玛莎拉蒂等25家汽车厂商,第一批支持Android Auto的汽车将于今年晚些时候上市,正式版本也将与Android L手机系统同步推出
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- 设置Eclipse缩进为4个空格,增强代码规范
- MySQL8.0.19开启GTID主从同步CentOS8