RAC的Bind方法
RAC提供了一堆可以提高开发效率的方法,比如filter
,map
,flattenMap
等值处理方法,几乎每个方法点到底,都能看到一个叫做bind
的方法.这个方法就是RAC相对底层的方法.弄明白它,对于理解RAC是非常有帮助的.
记录自己的进步
RAC提供了一堆可以提高开发效率的方法,比如filter
,map
,flattenMap
等值处理方法,几乎每个方法点到底,都能看到一个叫做bind
的方法.这个方法就是RAC相对底层的方法.弄明白它,对于理解RAC是非常有帮助的.
关于使用Cocoapods打包静态库或者是Framework的文章,网上一搜一堆.可是当你读完,发现用处有限.它们的都是用最简单的场景串了一遍打包的流程,而整个过程中的多个坑,却根本没有提及.这就造成了一个假象,Cocoapods打包framework是简单愉快的,放弃原来的创建framework的形式吧!结果,当热情满满的开发者去用的时候,发现已经入了歧途了!
本人目前正在处理一款语音框架的工作,所以正好整理出来,希望能够对大家有帮助!
关于如何安装Cocoapods
,在此就不赘述了.如果没有Cocoapods
使用经验,也不建议看这篇文章. 另外,建议将Cocoapods
升级到最新版本(包括最新的beta),升级命令如下:
1 | gem install cocoapods --pre |
通过命令创建一个规范规程(这个很重要,方便你的开发与验证)
1 | pod lib create YouFrameworkName |
接下来就是一些问题,根据实际情况选择.(我这开发的OC版本)
特别说明: 一定要创建Demo Application!这个对你的开发有极大的帮助!!
具体步骤也不赘述了,给大家几篇参考文章.做完就具备了基本的结构了.主要是想一块继续深入下去.
有一个问题需要注意: 如果你选择打包.a的静态库,那么cocoapods是不会给你生成头文件的 ,这就意味着,其实,你只能打包framework.
按照上面的两篇文章做完,你会发现.握草,根本不够项目用啊.我项目还有三方的framework
,还有三方的.a
库,还想添加pch
文件…
另外,关于各种路径的问题,例如:s.source_files
和s.header_dir
这些,经常会被Cocoapods报错:pattern匹配不到任何文件.其实,只要记住一个原则:你的库路径(可能是线上git库也可能是本地git库)+你的指定路径 = 要找的文件路径,那么就一定没问题. 例如我的库路径是::git => '/Users/kenny/Documents/LTVoiceAssistant'
而我指定的s.source_files = 'LTVoiceAssistant/Classes/**/*.{c,h,hh,m,mm,cpp,a,pch}'
,它们两个拼接,正好是我各种源码文件的路径.
在项目中,我们经常会有一些以文件形式存在的framework和.a,例如我项目中就有百度的语音识别和一个高德的.而由于某些原因,你不能用cocoapods将其管理,只能拖到项目中,cocoapods使用vendored_frameworks
和vendored_libraries
字段进行设置:
1 | s.ios.vendored_libraries = 'LTVoiceAssistant/Classes/libBDVoiceRecognitionClient.a', |
如果你不是从零开始,而是将其他项目的代码剥离打包framework的话,这个绝对会帮你大忙,因为cocoapods的验证,会检查你代码的依赖性,如果有照不到的头文件或者引入关系不对,是通不过验证的.podspec中,提供了两种方式添加pch文件.
方法一 : 使用s.prefix_header_contents
用法如下:
1 | s.prefix_header_contents = '#import "AHeader.h"','#import "BHeader.h"' |
可以看出,简单方便.但是也是因为简单,所以一些负责的宏之类的,你用这个是没法完成的.
方法二: 添加pch文件.
首先framework工程里(不是DemoApplication中)添加pch文件.然后将文件加入到编译的source中(如果你是拷贝进来的头文件)
最后,在podspec中,添加下面的信息:1
s.prefix_header_file = 'LTVoiceAssistant/Classes/Global/LTSpeech-prefix.pch'
在cocoapods的issue中,作者特别提到了.如果报找不到,那么是Xcode没找到,不是cocoapods,所以,确保将pch加入了编译.
如果你的代码中包含Xib和Storyboard,需要注意,这几个文件是需要添加到资源中的.1
s.resource = 'LTVoiceAssistant/Classes/Cells/*.xib'
之前写过一篇attribute((constructor))用法探究,当时是在看代码的时候,对它产生了偶遇.而这几天,越发发现这个__attribute__
的强大.作为一个iOS开发者,我试着总结了一下这个在我们日常开发中的应用.
相信对Swift有一定了解的人都知道它的下标语法.这个语法让类具备了像字典或者数组那样,利用下标获取一些东西的能力.但是,很多开发者或许不知道,OC中早就在Xcode4的时代,就已经有了这个语法.
正如数组和字典, OC中的下标也分为了索引和键位.
索引下标需要声明和实现这两个方法:
1 | - (id)objectAtIndexedSubscript:(NSUInteger)idx; |
键索引下标需要实现这两个方法:
1 | - (id)objectForKeyedSubscript:(id <NSCopying>)key; |
这么说还是有些抽象, 现在来具体看个例子:
1 | @interface BlackBox : NSObject |
然后使用方法:
1 | BlackBox *blackBox = [BlackBox new]; |
这个最好的感觉,就是封装细节.
现在比较火的路由,用这个方法去实现就比较好,例如:1
2
3routes[@"black module://rootController:23"] = ^(id param){
//逻辑代码
}
然后这个用方法来实现,也是okay的啊,为啥要用这个下标呢? 个人感觉,本身,我们编程工作,很大一部分的内容就是命名.而这个命名也是很容易出问题的地方.而下标的方式,让我们可以省去这个步骤.很简单的一个例子:array[10]
和 [array objectAtIndex:10]
你更愿意用哪个呢?
宏本身不难理解,但是往往嵌套多了,或者利用一些不常用的特性之后,会让人觉得迷惑.
在ProtocolKit
中有这么一段宏的定义:
1 | // Get container class name by counter |
当时知道:
##
连字符,通常用来拼接
__COUNTER__
计数器,一般用来后缀在变量上面,保证变量的唯一性.在程序中,每使用一次,这个数字就+1
,默认是0
再看实际拼接的结果:
1 | _pk_get_container_class(MyProtocol); |
一开始的时候在想, 不就是要拼接么,为何要弄那么多层嵌套.难道是故意增加复杂度,让人觉得高深? 还有变量前面的$
,是和shell中的一个意思? 表示变量?
遇到看不懂的东西,我喜欢先去掉,把自己知道的代码罗列出来.然后依次加上不懂得东西,看它对既有结果的改变.然后判断它的作用.
于是,我写了下面一个宏:
1 | #define _kn_get_container_class(prefix,protocol) prefix##_##protocol##_##__COUNTER__ |
然后使用:1
NSString * _kn_get_container_class(__kn,MyProtocol);
可是根据编译器的警告来看,并不是我想要的结果:
原来在##
的作用下,__COUNTER__
被当成了字面上的表示,并没有解析.
然后,根据作者的写法,把实现加深一层,改写为:
1 | #define _simpleifyGetContainerClass(prefix,protocol,counter) _simple_getContainerClass_imp(prefix,protocol,counter) |
调用
1 | NSString * _simpleifyGetContainerClass(__PKContainer_,MyProtocol,__COUNTER__); |
发现结果正确.
我这种写法,需要使用者传递多个参数,也已经必须嵌套一层了.作者在此基础上加上默认的参数实现,也是很合理的.
另外可以看到,这个$
符号,不加也可以,所以,个人猜想.这个和shell中使用变量
不是一回事.可能加上仅仅为了阅读者明白,这个地方是个变量.若理解不正确,请您指正.
之前项目中,封装过打印.当时就用到了可变参数的宏:
1 |
|
就是在定义的时候,以...
作为最后一个参数,使用的时候,__VA_ARGS__
就代指这一系列可变参数.
今天想找找关于宏的资料,发现GCC的文档中,也有关于可变参数宏的说明.在此,就不赘述了,想深入了解的,可以查看文档
今天在看ProtocolKit的源码,看到了这么一行代码.
1 | __attribute__((constructor)) static void _pk_extension_inject_entry(void) { |
主要造成疑惑的是 __attribute__((constructor))
,以前看过关于__attribute__
这个关键字的,大概还记得就是可以修饰类型,函数什么的.类似一个编译标记.但是具体用法忘记了.