本文主要介绍
1.Clang与LLVM
2.GDB与LLDB
3.homebrew与CocoaPods等
4.iOS系统框架
1.Clang与LLVM
LLVM项目的发展起源于2000年伊利诺伊大学厄巴纳-香槟分校维克拉姆·艾夫(Vikram Adve)与克里斯·拉特纳(Chris Lattner)的研究,他们想要为所有静态及动态语言创造出动态的编译技术。LLVM是以BSD授权来发展的开源软件。2005年,苹果电脑雇用了克里斯·拉特纳及他的团队为苹果电脑开发应用程序系统,LLVM为现今Mac OS X及iOS开发工具的一部分。
LLVM的命名最早源自于底层虚拟机(Low Level Virtual Machine)的首字母缩写,由于这个项目的范围并不局限于创建一个虚拟机,这个缩写导致了广泛的疑惑。LLVM开始成长之后,成为众多编译工具及低级工具技术的统称,使得这个名字变得更不贴切,开发者因而决定放弃这个缩写的意涵,现今LLVM已单纯成为一个品牌,适用于LLVM下的所有项目,包含LLVM中介码(LLVM IR)、LLVM除错工具、LLVM C++标准库等。
Xcode3之前,用的是GCC
Xcode3,GCC仍然保留,但是也推出了LLVM,苹果推荐LLVM-GCC混合编译器,但还不是默认编译器
Xcode4,LLVM-GCC成为默认编译器,但GCC仍保留
Xcode4.2,LLVM3.0成为默认编译器,纯用GCC不复可能
Xcode4.6,LLVM升级到4.2版本
Xcode5,LLVM-GCC被遗弃,新的编译器是LLVM5.0,从GCC过渡到LLVM的时代正式完成
Clang - a C language family frontend for LLVM
Clang(发音为/ˈklæŋ/) 是一个C、C++、Objective-C和Objective-C++编程语言的编译器前端。它采用了底层虚拟机(LLVM)作为其后端。它的目标是提供一个GNU编译器套装(GCC)的替代品。作者是克里斯·拉特纳,在苹果公司的赞助支持下进行开发,而源代码授权是使用类BSD的伊利诺伊大学厄巴纳-香槟分校开源码许可。
Clang项目包括Clang前端和Clang静态分析器等。
Clang的在出生之前就已经明确了他的使命——干掉该死的GCC。有了LLVM+Clang,从此,苹果的开发面貌焕然一新。从此摆脱了GCC的限制。客观的说GCC是有很多的优点,例如支持多平台,很流行,基于C无需C++编译器即可编译。这些优点到苹果那就可能是缺点了,苹果需要的是——快。这正是Clang的优点,除了快,它还有与GCC兼容,内存占用小,诊断信息可读性强,易扩展,易于IDE集成等等优点。有个测试数据:Clang编译Objective-C代码时速度为GCC的3倍。
iOS编译过程
编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化,根据不同的系统架构生成不同的机器码。
C++,Objective C都是编译语言。编译语言在执行的时候,必须先通过编译器生成机器码。
如上图所示,在xcode按下cmd+B之后的工作流程。
预处理(Pre-process):他的主要工作就是将宏替换,删除注释展开头文件,生成.i文件。
词法分析 (Lexical Analysis):将代码切成一个个 token,比如大小括号,等于号还有字符串等。是计算机科学中将字符序列转换为标记序列的过程。
语法分析(Semantic Analysis):验证语法是否正确,然后将所有节点组成抽象语法树 AST 。由 Clang 中 Parser 和 Sema 配合完成
静态分析(Static Analysis):使用它来表示用于分析源代码以便自动发现错误。
中间代码生成(Code Generation):开始IR中间代码的生成了,CodeGen 会负责将语法树自顶向下遍历逐步翻译成 LLVM IR,IR 是编译过程的前端的输出后端的输入。
优化(Optimize):LLVM 会去做些优化工作,在 Xcode 的编译设置里也可以设置优化级别-01,-03,-0s,还可以写些自己的 Pass,官方有比较完整的 Pass 教程: Writing an LLVM Pass — LLVM 5 documentation 。如果开启了 bitcode 苹果会做进一步的优化,有新的后端架构还是可以用这份优化过的 bitcode 去生成。
生成目标文件(Assemble):生成Target相关Object(Mach-o)
链接(Link):生成 Executable 可执行文件
经过这一步步,我们用各种高级语言编写的代码就转换成了机器可以看懂可以执行的目标代码了。
环境搭建
cd /opt
sudo mkdir llvm
sudo chown `whoami` llvm
cd llvm
export LLVM_HOME=`pwd`
git clone -b release_39 [email protected]:llvm-mirror/llvm.git llvm
git clone -b release_39 [email protected]:llvm-mirror/clang.git llvm/tools/clang
git clone -b release_39 [email protected]:llvm-mirror/clang-tools-extra.git llvm/tools/clang/tools/extra
git clone -b release_39 [email protected]:llvm-mirror/compiler-rt.git llvm/projects/compiler-rt
mkdir llvm_build
cd llvm_build
cmake ../llvm -DCMAKE_BUILD_TYPE:STRING=Release
make -j`sysctl -n hw.logicalcpu`
文件很多很大,需要下载一段时间
Clang Static Analyzer静态代码分析
clang 静态分析是通过建立分析引擎和 checkers 所组成的架构,这部分功能可以通过 clang —analyze 命令方式调用。
命令行执行
通过clang -cc1 -analyzer-checker-help
可以列出能调用的 checker,但这些checker并不是所有都是默认开启的
这里使用一个默认关闭的checker-alpha.security.ArrayBoundV2作为例子进行操作
$ clang -cc1 -analyzer-checker-help
alpha.core.BoolAssignment Warn about assigning non-{0,1} values to Boolean variables
alpha.core.CastSize Check when casting a malloced type T, whether the size is a multiple of the size of T
alpha.core.CastToStruct Check for cast from non-struct pointer to struct pointer
alpha.core.FixedAddr Check for assignment of a fixed address to a pointer
alpha.core.IdenticalExpr Warn about unintended use of identical expressions in operators
alpha.core.PointerArithm Check for pointer arithmetic on locations other than array elements
alpha.core.PointerSub Check for pointer subtractions on two pointers pointing to different memory chunks
alpha.core.SizeofPtr Warn about unintended use of sizeof() on pointer expressions
alpha.cplusplus.NewDeleteLeaks Check for memory leaks. Traces memory managed by new/delete.
alpha.cplusplus.VirtualCall Check virtual function calls during construction or destruction
...
alpha.security.ArrayBound Warn about buffer overflows (older checker)
alpha.security.ArrayBoundV2 Warn about buffer overflows (newer checker)
alpha.security.MallocOverflow Check for overflows in the arguments to malloc()
alpha.security.ReturnPtrRange Check for an out-of-bound pointer being returned to callers
...
core.CallAndMessage Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)
core.DivideZero Check for division by zero
core.DynamicTypePropagation Generate dynamic type information
core.NonNullParamChecker Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute
core.NullDereference Check for dereferences of null pointers
core.StackAddressEscape Check that addresses to stack memory do not escape the function
...
unix.API Check calls to various UNIX/Posix functions
unix.Malloc Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().
unix.MallocSizeof Check for dubious malloc arguments involving sizeof
unix.MismatchedDeallocator Check for mismatched deallocators.
unix.cstring.BadSizeArg Check the size argument passed into C string functions for common erroneous patterns
unix.cstring.NullArg Check for null pointers being passed as arguments to C string functions
可以使用 -enable-checker 和 -disable-checker 开启和禁用具体的 checker 或者 某种类别的 checker。
$ scan-build -enable-checker alpha.security.ArrayBoundV2 ... # 启用数组边界检查
当然,使用scan-build
启用的checker
只适用于使用scan-build
生成的html报告。 scan-build
在编译安装 llvm/clang 之后可以在/llvm/tools/clang/tools/scan-build
目录下找到
//允许未被默认允许的check并进行代码分析并将输出结果输出至网页
./scan-build -enable-checker alpha.security.ArrayBoundV2 --use-analyzer=/opt/llvm/llvm_build/bin -V xcodebuild -project /Users/yuhao/TestClang/TestClang.xcodeproj -sdk iphonesimulator10.3
我们在TestClang.xcodeproj的main.m文件中插入一段数组越界的代码
int main(){
@autoreleasepool {
int a[2];
int i;
for (i = 0; i < 3; i++){
a[i] = 0;
}
}
return 0;
}
然后执行上面的命令,会导出这样的一个界面
查看报表
https://upload-images.jianshu...
报表中提示了该代码有数组越界的问题。
Xcode执行
Xcode本身已经自带了静态检测的功能,可以通过Product-Analyze来执行静态检测,这也只是用自带的clang去执行,如果想用其他的版本,比如自己编译clang,就需要通过命令来设置。
在Xcode的Product选项卡下有Analyze的选项,Xcode中默认提供了一些checkers。
Usage: set-xcode-analyzer [options]
Options:
-h, --help show this help message and exit
--use-checker-build=PATH
Use the Clang located at the provided absolute path,
e.g. /Users/foo/checker-1
--use-xcode-clang Use the Clang bundled with Xcode
可以看到,它有2个选项,
--use-checker-build
:用于将xcode的clang版本切换成设定的版本 --use-xcode-clang
:用于将xcode的clang版本切换回去
注:在执行上面命令的时候,需要退出xcode执行;且需要用sudo的方式运行。
依然使用上面的project文件,在Build Settings添加参数,如图
-Xanalyzer -analyzer-checker=alpha.security.ArrayBoundV2
然后cmd+shift+b
在Xcode中也出现了和报表同样的提示。
关于checker的开发可以看这里。
weak的实现 runtime
是如何实现在weak
修饰的变量的对象在被销毁时自动置为nil
的呢?一个普遍的解释是:runtime
对注册的类会进行布局,对于weak
修饰的对象会放入一个hash
表中。用weak
指向的对象内存地址作为key
,当此对象的引用计数为0
的时候会dealloc
,假如weak
指向的对象内存地址是a
,那么就会以a
为键在这个weak
表中搜索,找到所有以a
为键的weak
对象,从而设置为nil
。
weak
指针的实现借助Objective-C
的运行时特性,runtime
通过 objc_storeWeak
, objc_destroyWeak
和 objc_moveWeak
等方法,直接修改__weak
对象,来实现弱引用。
objc_storeWeak
函数,将附有__weak
标识符的变量的地址注册到weak
表中,weak
表是一份与引用计数表相似的散列表。
而该变量会在释放的过程中清理weak
表中的引用,变量释放调用以下函数:
dealloc
_objec_rootDealloc
object_dispose
objc_destructInstance
objc_clear_deallocating
在最后的objc_clear_deallocating
函数中,从weak
表中找到弱引用指针的地址,然后置为nil
,并从weak
表删除记录。
关于ARC更多实现请参阅探究ARC
2.GDB与LLDB
我们在开发iOS程序的时候常常会用到调试跟踪,如何正确的使用调试器来debug十分重要。xcode里有内置的Debugger,老版使用的是GDB,xcode自4.3之后默认使用的就是LLDB了。
GDB:
UNIX及UNIX-like下的调试工具。
LLDB:
LLDB是个开源的内置于XCode的具有REPL(read-eval-print-loop)特征的Debugger,其可以安装C++或者Python插件。
所以他们两个都是调试用的Debugger,只是LLDB是比较高级的版本,或者在调试开发iOS应用时比较好用,不然人家苹果为什么换成了LLDB了呢!
lldb与gdb命令名的对照表:http://lldb.llvm.org/lldb-gdb.html
LLDB的使用
在程序里你需要的地方设置断点。当断点断住的时候你就能看到我们进入LLDB调试器了。
这时我们就可以使用一些LLDB命令来进行一些调试了。
调试快捷键:(Xcode常用快捷键)
command+shift+Y 打开调试窗口
command+Y 调试运行程序
command+option+P 继续
command+shift+O 跳过
command+shift+I 进入
command+shift+T 跳出
help命令
help会列出所有命令列表,用户加载的插件一般来说列在最后。
执行help 可以打印指定command的帮助信息。
比如:help print会打印内建命令print的使用帮助。
print命令
print命令的简化方式有prin pri p,唯独pr不能用来作为检查,因为会和process混淆,幸运的是p被lldb实现为特指print。
实际上你会发现,lldb对于命令的简称,是头部匹配方式,只要不混淆,你可以随意简称某个命令。
例如:
最前面的(int)是类型。$是命令结果的引用名,使用$0可以进行print $0 + 7这样打印出17。
输出view 下 subview 的数量。
由于 subview 的数量是一个 int 类型的值,所以我们使用命令p: (lldb)p (int)[[[self view] subviews] count]
直接调用方法改变背景颜色之类
其实使用p,po,call都可以调用方法,只是p和po都是用于输出的有返回值的。call一般只在不需要显示输出,或是方法无返回值时使用。 (lldb)p [self.view setBackgroundColor:[UIColor redColor]]
(lldb)p (void)[CATransaction flush]
上述的p一般使用call比较好,因为方法是没有返回值的。
po命令
命令po跟p很像。p输出的是基本类型,po输出的Objective-C对象。调试器会输出这个 object 的 description。
例如:
expression命令
expression的简写就是e。可以用expression来声明新的变量,也可以改变已有变量的值。我们看到e声明的都是$开头的变量。我们在使用时也需要加上$符号。
例如:
创建新的变量
注意:如果上面这里输入以下命令,会发生错误。说明lldb无法判定某一步的计算结果是什么数据类型,这时需要强制类型转换来告诉lldb。
(lldb) p [[$array objectAtIndex:0] characterAtIndex:0]
error: no known method '-characterAtIndex:'; cast the message send to the method's return type
error: 1 errors parsing expression
(lldb) p (char)[[$array objectAtIndex:0] characterAtIndex:0]
'o'
修改已有变量
image命令
image 命令可用于寻址,有多个组合命令。比较实用的用法是用于寻找栈地址对应的代码位置。 下面我写了一段代码
NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSLog(@"%@",arr[2]);
这段代码有明显的错误,程序运行这段代码后会抛出下面的异常:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
0 CoreFoundation 0x0000000101951495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001016b099e objc_exception_throw + 43
2 CoreFoundation 0x0000000101909e3f -[__NSArrayI objectAtIndex:] + 175
3 ControlStyleDemo 0x0000000100004af8 -[RootViewController viewDidLoad] + 312
4 UIKit 0x000000010035359e -[UIViewController loadViewIfRequired] + 562
5 UIKit 0x0000000100353777 -[UIViewController view] + 29
6 UIKit 0x000000010029396b -[UIWindow addRootViewControllerViewIfPossible] + 58
7 UIKit 0x0000000100293c70 -[UIWindow _setHidden:forced:] + 282
8 UIKit 0x000000010029cffa -[UIWindow makeKeyAndVisible] + 51
9 ControlStyleDemo 0x00000001000045e0 -[AppDelegate application:didFinishLaunchingWithOptions:] + 672
10 UIKit 0x00000001002583d9 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 264
11 UIKit 0x0000000100258be1 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1605
12 UIKit 0x000000010025ca0c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 660
13 UIKit 0x000000010026dd4c -[UIApplication handleEvent:withNewEvent:] + 3189
14 UIKit 0x000000010026e216 -[UIApplication sendEvent:] + 79
15 UIKit 0x000000010025e086 _UIApplicationHandleEvent + 578
16 GraphicsServices 0x0000000103aca71a _PurpleEventCallback + 762
17 GraphicsServices 0x0000000103aca1e1 PurpleEventCallback + 35
18 CoreFoundation 0x00000001018d3679 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
19 CoreFoundation 0x00000001018d344e __CFRunLoopDoSource1 + 478
20 CoreFoundation 0x00000001018fc903 __CFRunLoopRun + 1939
21 CoreFoundation 0x00000001018fbd83 CFRunLoopRunSpecific + 467
22 UIKit 0x000000010025c2e1 -[UIApplication _run] + 609
23 UIKit 0x000000010025de33 UIApplicationMain + 1010
24 ControlStyleDemo 0x0000000100006b73 main + 115
25 libdyld.dylib 0x0000000101fe95fd start + 1
26 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
现在,我们怀疑出错的地址是0x0000000100004af8(可以根据执行文件名判断,或者最小的栈地址)。为了进一步精确定位,我们可以输入以下的命令:
(lldb)image lookup --address 0x0000000100004af8
(lldb)im loo -a 0x0000000100004af8
命令执行后返回:
Address: ControlStyleDemo[0x0000000100004af8] (ControlStyleDemo.__TEXT.__text + 13288)
Summary: ControlStyleDemo`-[RootViewController viewDidLoad] + 312 at RootViewController.m:53
我们可以看到,出错的位置是RootViewController.m的第53行。
设置断点触发条件
LLDB与GDB总结
原理
编译时输出带调试信息的程序,调试信息包含了指令地址、对应源代码及行号,指令完成后回调给调试器。
gdb/lldb常用命令
- b:设置断点break。
- r:运行run。
- n:单步调试next。
- s:跳入函数step。
- finish:跳出函数。
- p a:打印a的内容print。
- c:继续,直到下一个断点continue。
2.1打包编译组件
xctoo简介:facebook那帮人,耐不住每天打包的烦恼,搞了一些自动化组件工具。基于xcodebuild封装了一层形成了xctool。
xctool有哪些好处呢?
1、它可以从命令行构建和运行单元测试,这和Xcode.app从图形化界面上达到一样的效果。如果你为iOS设置了持续集成系统,那么这就非常重要了。你想要能够自动化运行测试,那些测试与你的开发人员在本地计算机上运行的完全相同,而xcodebuild不会用和Xcode.app相同的方式来构建和运行测试。在Xcode 4中,苹果把单元测试集成到了Xcode中——与“构建”和“运行”一起,有一个新的“测试”动作;使用Xcode scheme,你可以选择启用或者禁用哪些单元测试;如果你依赖于iOS模拟器(也就是应用程序测试)来编写测试,那么Xcode会自动载入模拟器并运行测试。这些都是很大的改进,但看起来苹果并没有把这些改进融入到xcodebuild中,那使得自动化构建和测试非常困难。
2、 另一个重大的问题是构建和测试失败的报告。使用xcodebuild,你会得到大量文本输出,其中包含编译命令、编译错误和警告以及OCUnit的测试输出。如果你想要自动确定哪个组件编译失败,或者哪个单元测试失败,那么你就需要编写自己的正则表达式解析器,那也是我们和其他iOS社区中的人一直在做的工作。那会有效果,但实在很麻烦。有了xctool,我们会让xcodebuild和OCUnit测试运行器把构建输出和测试结果作为JSON对象的结构化流输出。 这让我们可以很容易地以需要的形式来显示构建和测试结果。例如,我们创建了一个报表,以吸引人的、带有颜色的输出形式来显示结果(https://fpotter_public.s3.amazonaws.com/xctool-uicatalog.gif)。 还有人使用这来把测试结果输出为JUnit XML,那在流行的Jenkins构建系统中会显示得很好。>>>>
xctool的使用:常用命令在他们工程的readme里有详细描述和例子:https://github.com/facebook/x...
xctool 不支持指定target如 -target
; 必须用scheme例如
- path/to/xctool.sh \
- -project YourProject.xcodeproj \
- -scheme YourScheme \
- build
xctool指定打印报告
- path/to/xctool.sh \
- -workspace YourWorkspace.xcworkspace \
- -scheme YourScheme \
- -reporter plain:/path/to/plain-output.txt \
- build
可以指定的格式如下
- pretty: a text-based reporter that uses ANSI colors and unicode symbols for pretty output (the default).
- plain: like _pretty_, but with no colors or unicode.
- phabricator: outputs a JSON array of build/test results which can be fed into the Phabricator code-review tool.
- junit: produces a JUnit/xUnit compatible XML file with test results.
- json-stream: a stream of build/test events as JSON dictionaries, one per line (example output).
- json-compilation-database: outputs a JSON Compilation Database of build events which can be used by Clang Tooling based tools, e.g. OCLint.
- user-notifications: sends notification to Notification Center when action is completed (example notifications).
- teamcity: sends service messages to TeamCity Continuous Integration Server
下面用xcodebuild和xctool实际动手打几个包来练练手。
一:测试了半天xcode8以后不支持xctool了 汗!!!
二:我们回到xcodebuild上
project_path=$(pwd)
echo "project_path:${project_path}"
schemeName="FunnyProject"
outPutPath="${project_path}/outputDir"
echo "outputPath:${outPutPath}"
xcodebuild clean -workspace ${schemeName}.workspace -scheme ${schemeName} -configuration Debug
xcodebuild -project $schemeName.xcodeproj -scheme $schemeName clean
xcodebuild archive -project $schemeName.xcodeproj -scheme $schemeName -archivePath "${outPutPath}/${schemeName}.xcarchive" -configuration Debug
xcodebuild -archivePath "${outPutPath}/${schemeName}.xcarchive" -exportPath "${outPutPath}/${schemeName}.ipa" -exportOptionsPlist "${outPutPath}/ExportOptions.plist" -exportArchive
//这里有个参数exportOptionsPlist 需要收到打包导出文件夹里有这个文件,相当于一个配置文件,用这个文件来导出包,把这个文件copy到当前目录即可
-exportOptionsPlist "${outPutPath}/${schemeName}.plist"
xcodebuild -exportArchive -exportSigningIdentity 'Developer ID Application: My Team'
#xcodebuild -exportArchive -archivePath
xctool -workspace GWMovie.xcworkspace -scheme GWMovie -sdk iphonesimulator run-tests
echo "${SECONDS}s"
3.包管理器
MacPorts
MacPorts依赖于BSD的软件包管理工具(port),它的工作方式是从仓库中下载软件包以及其依赖库,然后在本机中编译安装。
MacPorts的理念是尽量减少对系统现有库的依赖,因此它需要下载许多基础库,然后编译安装到系统中。这样做最大的问题在于下载时间长,编译时间长,最大的好处就是不会破坏系统原有软件包。
Homebrew
Homebrew与MacPorts的工作方式类似,也是从仓库中下载软件包以及其依赖库,然后在本机中编译安装。
Homebrew的理念是尽量使用系统中存在的库,且软件包都安装到/usr/local目录里,最大的好处就是下载编译时间短于MacPorts,安装简单,且无需root用户权限来安装。
Homebrew几乎快成为Mac OSX系统下事实上的标准软件包管理工具了
CocoaPods
iOS 和 OS X下的一个第三方库管理工具,类似的iOS工具还有Carthage(比较轻量级,需要手动配置,非侵入式),与Java里的Maven也比较类似,但是没有maven的构建、运行程序、打包等功能,仅仅是库依赖配置和库版本管理工具。
作用:依赖库版本管理、库依赖自动配置;
系统架构
一、iOS系统架构
用户体验层(The User Experience Layer)
应用软件开发框架层(The Application Frameworks Layer)
核心开发框架层(The Core Frameworks)
系统内核核心层(Darwin)
概述:
1、Darwin
Darwin是一种类似unix的操作系统,他的核心是XNU。
XNU是一种混合式内核。结合了mach与BSD两种内核。
Mach是微内核实现。
BSD实现在Mach的上层,这一层提供的API 支持了POSIX标准模型。在XNU中主要实现了一些高级的API与模块。
1.1、Mach 微内核简介
在XNU中主要完成以下几个功能:
进程与线程的抽象
虚拟内存管理
任务调度
进程间通信
1.2、BSD 内核简介
BSD 实现在Mach的上层,这一层提供的API 支持了POSIX标准模型。在XNU中主要实现了一些高级的API与模块。
UNIX 进程模型。
POSIX 线程模型即pthread,以及相关的同步功能。
UNIX的用户与组管理。
网络协议栈(BSD Socket API),符合POSIX 模型。
文件系统/设备系统。
1.3、libKern
实现了一个C+ +的子集(以库的形式为支持C+ +提供了运行时),为I/O kit 提供基础设施
1.4、I/O kit
I/O kit 是XNU 不同于其他操作系统的设备驱动框架。IOKit是一个面向对象的驱动模型框架,它是早期DriverKit的一个翻版,Driver Kit是使用Objective-C写的,而IOKit是一个C+ +的驱动架构,它在DriverKit的基础上做了很大的改进,比如IOKit可以写在用户空间跑的驱动(虽然大多仍是跑在内核空间上的),因而驱动挂了而系统不会挂。另外IOKit考虑到了计算机发展的趋势,所以在电源管理、即插即用、动态加载上做得更好。
两个基础框架
iOS应用程序基于Foundation和UIKit框架
1. Foundation
在你开发程序时,主要使用框架就是Foundation和UIKit,因为它们包含了你需要的大部分东西。
- Foundation框架为所有的应用程序提供基本系统服务
你的应用程序,UIKit和其它的框架都是建立在Foundation框架上面的。Foundation框架是用Object-C对CoreFoundation框架里许多特性的封装。 - 使用Foundation可以:
- 创建和管理集合,比如数组和字典
- 访问存储在应用程序里的图片和其它资源
- 创建和管理字符串
- 提交和接收通知
- 创建日期和时间对象
- 自动发现IP网络上的设备
- 操作URL流
- 执行异步代码
你已经在《Your First iOSApp》里使用到了Foundation框架。比如,你使用一个NSString类的实例存储用户输入的userName。你还使用了Foundation框架的initWithFormat方法创建了一个字符串。
UIKit框架提供创建基于触摸用户界面的类
2. UIKit
所有的iOS应用程序都基于UIKit,你不能是应用程序脱离这个框架。UIKit提供了在屏幕上绘制的机制,捕获事件,和创建通用用户界面元素。UIKit也通过管理显示在屏幕上的组件来组织复杂的项目。
- 使用UIKit可以:
- 构建和管理你的用户界面
- 捕获触摸和基于移动的事件
- 呈现文字和web内容
- 优化你的多任务程序
- 创建定制的用户界面元素
在《YouFirstiOS AppTutorial》里,你也使用到了UIKit。当你仔细查看程序是怎么运行起来的时候,你会看到UIApplicationMain函数创建一个UIApplication类的实例,这个实例会捕获进来的用户事件。你实现UITextFieldDelegate协议,然后在用户按下Done时隐藏键盘。实际上,你是在使用UIKit创建用户界面上的UITextField,UILabel,和UIButton类。
你需要知道的其它重要的框架
Core Data , Core Graphics, CoreAnimation,和OpenGLES框架都是高级的技术。所以这些框架对于你开发应用程序也是很重要的,它们都需要时间去学习和掌握。
1. CoreData框架管着理应用程序数据模型
Core Data提供对象的管理,使用CoreData,你可以创建模型对象,并管理这些对象。你管理这这些对象间的联系并修改数据。CoreData提供的内建SQLlite技术可以高效的管理数据。
使用Core Data可以:
- 在库里存储和接收对象
- 提供基本的undo/redo
- 自动验证属性值
- 过滤、分组和优化内存中的数据
- 用[NSFetchedResultsController]管理表视图中的结果
- 支持基于文档的应用程序
2. CoreGraphics框架帮助你创建图形
高质量的图形对于所有的iOS应用程序都是很重要的。在iOS中最简单且最快捷的创建图形的方式是使用UIKit框架提供的基于预渲染图形的视图和控件,然后让UIKit和iOS完成绘制。但是当你需要创建复杂的图形时,CoreGraphics则提供了更底层的库来帮助你。
使用Core Graphics可以:
- 创建基于路径的绘图
- 抗锯齿渲染
- 添加梯度、图片和颜色
- Use coordinate-spacetransformations.
- 创建、显示和分析PDF文档
3. CoreAnimation允许你创建高级的动画和虚拟效果
UIKit提供建立在Core Animation之上的动画。如果你需要比UIKit能力更高级的功能,可以直接使用CoreAnimation。Core Animation接口包含在Quartz Core框架里。使用CoreAnimation可以创建嵌套的对象,并且可以对它们操作、旋转、缩放和转换。使用Coreanimation,你可以创建动态的用户界面而不用使用更底层的图形API,如OpenGL ES。
使用Core Animation可以:
- 创建定制动画
- 添加定时函数和图形
- 支持帧动画
- Specify graphical layoutconstraints.
- Group multiple-layerchanges into anatomic update.
4. OpenGL ES框架提供2D和3D绘图工具
OpenGL ES支持2D和3D绘图,Apple的OpenGL ES实现通过硬件提供了高速的全屏游戏式的应用程序。
使用OpenGL ES可以:
- 创建2D和3D图形
- 创建更复杂的图形,比如数据虚拟化、模拟飞行,或者视频游戏
- 访问底层图形设备
根据需要向项目中添加其它框架
还有许多框架可以添加到你的程序里。当你决定使用一个框架但项目里却没有引入这个框架时,你就需要将它加入到你的项目里。
将别的框架添加到工程里
1 打开工程
2 点击项目名,显示project editor
3 在TARGETS列表中选中要添加框架的工程
4 点击project editor顶部的BuildPhases
5 点击Link Binary WithLibraries前面的三角形打开这个分组
6 通过点击添加(+)来添加一个框架
7 在列表中选择一个框架,然后点击Add按钮