xcode Frameworks,Libraries,and Embedded Content

import 和include
#include做的事情其实就是简单的复制粘贴,将目标.h文件中的内容一字不落地拷贝到当前文件中,并替换掉这句include,而#import实质上做的事情和#include是一样的,只不过OC为了避免重复引用可能带来的编译错误(这种情况在引用关系复杂的时候很可能发生,比如B和C都引用了A,D又同时引用了B和C,这样A中定义的东西就在D中被定义了两次,重复了),而加入了#import,从而保证每个头文件只会被引用一次。

实质上import也还是拷贝粘贴,这样就带来一个问题:当引用关系很复杂,或者一个头文件被非常多的实现文件引用时,编译时引用所占的代码量就会大幅上升(因为被引用的头文件在各个地方都被copy了一遍)。为了解决这个问题,C系语言引入了预编译头文件(PreCompiled Header),将公用的头文件放入预编译头文件中预先进行编译,然后在真正编译工程时再将预先编译好的产物加入到所有待编译的Source中去,来加快编译速度。比如iOS开发中Supporting Files组内的.pch文件就是一个预编译头文件,默认情况下,它引用了UIKit和Foundation两个头文件–这是在iOS开发中基本每个实现文件都会用到的东西。

于是理论上说,想要提高编译速度,可以把所有头文件引用都放到pch中。但是这样面临的问题是在工程中随处可用本来不应该能访问的东西,而编译器也无法准确给出错误或者警告,无形中增加了出错的可能性。

模块(Modules)

于是Modules诞生了。Modules相当于将框架进行了封装,然后加入在实际编译之时加入了一个用来存放已编译添加过的Modules列表。如果在编译的文件中引用到某个Modules的话,将首先在这个列表内查找,找到的话说明已经被加载过则直接使用已有的,如果没有找到,则把引用的头文件编译后加入到这个表中。这样被引用到的Modules只会被编译一次,但是在开发时又不会被意外使用到,从而同时解决了编译时间和引用泛滥两方面的问题。

稍微追根问底,Modules是什么?其实无非是对框架进行了如下封装,拿UIKit为例:

framework module UIKit {
  umbrella header "UIKit.h"
  module * {export *}
  link framework "UIKit"
}

这个Module定义了首要头文件(UIKit.h),需要导出的子modules(所有),以及需要link的框架名称(UIKit)。需要指出的是,现在Module还不支持第三方的框架,所以只有SDK内置的框架能够从这个特性中受益。另外,在C++的源代码中,Modules也是被禁用的。

怎么用Module呢

关于普通开发者使用的这个新特性的方法,Apple在LLVM5.0(也就是Xcode5带的最新的编译器前端中)引入了一个新的编译符号@import,使用@符号将告诉编译器去使用Modules的引用形式,从而获取好处,比如想引用MessageUI,可以写成

	
@import MessageUI;

在使用上,这将等价于以前的#import <MessageUI/MessageUI.h>,但是将使用Modules的特性。如果只想使用某个特性的.h文件,比如#import <MessageUI/MFMailComposeViewController.h>,对应写作

	
@import MessageUI.MFMailComposeViewController;

当然,如果对于以前的工程,想要使用新的Modules特性,如果要把所有头文件都这样一个一个改成@import的话,会是很大的一个工作量。Apple自然也考虑到了这一点,于是对于原来的代码,只要使用的是iOS7或者MacOS10.9的SDK,在Build Settings中将Enable Modules(C and Objective-C)打开,然后保持原来的#import写法就行了。是的,不需要任何代码上的改变,编译器会在编译的时候自动地把可能的地方换成Modules的写法去编译的。

然后讲一下xcode引入系统库和第三方库的方式。

举个例子,有人音频编码的时候

#import <AudioToolbox/AudioToolbox.h>

注释掉上面这句引入后,代码可以正常通过编译,寻找原因。猜测是不是跟·Foundation·和UIKit一样,不用导入xcode和import 就可以正常使用。因为xcode创建一个项目时,有些默认库是自动包含在内的。

Modules 第一次出现在2012年开发者大会上,它对库的封装比以往任何时候更加清洁。不需要预处理逐行的用文件所有内容替换#import指令。一个Modules包含了一个库到自包含的块中。就像pch文件预编译一样,提升了编译速度,也不需要在pch文件中声明你要引入的库。

一个Modules不仅告诉编译器哪些头文件组成了Modules,而且还告诉编译器什么需要链接。这个就解救了你不用你去手动的链接框架。这虽然是一件小事,但是能让开发更加简单就是一件好事。

怎样使用Modules

Modules的使用相当简单。对于存在的工程,第一件事情就是使这个功能生效。你可以在项目的Build Settings通过搜索Modules找到这个选项,改变Enable Modules 选项为YES,像这样:



 

所有的新工程都是默认开启这个功能的,但是你应该在你所有存在的工程内都开启这个功能。

Autolinking

Autolinking是Modules的附赠小惊喜,因为在module定义的时候指定来link framework,所以在编译module时LLVM会将所涉及到的框架自动帮你写到link里去,不再需要到编译设置里去添加了。即开发者不需要手动建立框架关联,引入头文件将为相应的框架建立自动关联。

Link Frameworks Automatically:这个选项就是用来开启或者关闭自动连接框架功能的,默认是开启的,如果一旦关闭这个选项,你的工程就会报一大堆的错误了,用户可以试一试,关闭这个功能,然后你必须手动导入一个一个框架,这对于开发者来说,无疑是一个灾难性的事件。

framework之Embed、Signing

当我们点击xcode工程的target时,可以看到在Build Phases一样看到framework可选的状态有几种:在xcode 10及之前,有三种状态:Do Not EmbedEmbed & SignEmbed Without Signing

Embed:嵌入,用于动态库,动态库在运行时链接,所以它们需要被打进bundle里面。如何判断呢?使用终端执行:

file frameworkToLink.framework/frameworkToLink
//pwd 的地址是包含frameworkToLink.framework的文件夹

如果返回:

  • current ar archive:说明是静态库,选择Do not embed
  • Mach-0 dynamically:说明是动态库,选择Embed

静态库和动态库的区别

  • 静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝,存在形式:.a和.framework
  • 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。存在形式:.dylib和.framework

系统的.framework是动态库,我们自己建立的.framework一般是静态库。

*Signing:只用于动态库,如果已经有签名了就不需要再签名。如何判断呢?使用终端执行:

codesign -dv frameworkToLink.framwork

如果返回:

  • code object is not signed at all 或者 adhoc:选择Embed and sign
  • 其它:表示已经正确签名,选择Embed Without Signing

 参考:写iOS程序时可以不用导入Foundation和UIKit框架的原因

参考:Xcode Modules与Autolinking机制

参考:iOS framework之Embed、Signing

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值