前言
Objective-C 一个一直以来令人诟病的地方就是没有命名空间,在应用开发时,所有的代码和引用的静态库最终都会被编译到同一个域和二进制中。这样的后果是一旦我们有重复的类名的话,就会导致编译时的冲突和失败。为了避免这种事情的发生,Objective-C 的类型一般都会加上两到三个字母的前缀,比如 Apple 保留的 NS 和 UI 前缀,各个系统框架的前缀 SK (StoreKit),CG (CoreGraphic) 等。Objective-C 社区的大部分开发者也遵守了这个约定,一般都会将自己名字缩写作为前缀,把类库命名为 AFNetworking 或者 MBProgressHUD 这样。这种做法可以解决部分问题,至少我们在直接引用不同人的库时冲突的概率大大降低了,但是前缀并不意味着不会冲突,有时候我们确实还是会遇到即使使用前缀也仍然相同的情况。另外一种情况是可能你想使用的两个不同的库,分别在它们里面引用了另一个相同的很流行的第三方库,而又没有更改名字。在你分别使用这两个库中的一个时是没有问题的,但是一旦你将这两个库同时加到你的项目中的话,这个大家共用的第三方库就会和自己发生冲突了。
在 Swift 中,由于可以使用命名空间了,即使是名字相同的类型,只要是来自不同的命名空间的话,都是可以和平共处的。和 C# 这样的显式在文件中指定命名空间的做法不同,Swift 的命名空间是基于 module 而不是在代码中显式地指明,每个 module 代表了 Swift 中的一个命名空间。也就是说,同一个 target 里的类型名称还是不能相同的。
<a href="http://swifter.tips/namespace/?utm_source=tuicool&utm_medium=referral">原文链接</a>(侵权删)
1.初识
我们来看看如下代码的打印,这是我讲两个控制器作为MainViewController的childvc的代码,只做讲解
import UIKit
class MainViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
setupChildViewController(TestFirstViewController())
setupChildViewController(TestSecondViewController())
}
private func setupChildViewController(vc:UIViewController) {
print(vc)
addChildViewController(vc)
}
}
我们来看看打印结果,如下图
我们看到,打印的控制器前面有nameSpaceTest
的打印显示,这里nameSpaceTest就是我们所说的命名空间的名称,一般来说命名空间是我们的项目名称
1.1修改命名空间
我们再来看看如何修改我们项目的命名空间,如下图
在项目中,build settings下搜索product name之后双击修改即可,如图我吧命名空间改成iOSCoderZZJ,在运行上面的那段代码,看看控制台的打印情况,如下图
从图片的打印看来,命名空间已经被咱们修改了
1.2动态加载命名空间
在开发中,咱们可以轻而易举的得知自己项目的命名空间,但是写在代码中,如果用字符串"nameSpaceTest"
或者"iOSCoderZZJ"
写死,肯定会觉得非常low吧,那么咱们就来看看如何动态的获取项目的命名空间,众所周知,项目的所有配置信息都在info.plist中,那么我们就去找找看吧,如下图
点击后,如下图的key对应的就是项目的命名空间信息
既然我们都知道了套路,看看代码如何写吧
//动态获取命名空间(常规写法出现的错误写法)
let ns = NSBundle.mainBundle().infoDictionary["CFBundleExecutable"]
这样我们就拿到了项目的命名空间,但是!!!!!!!如果你复制上面这句代码,一定会报错的,这里要插播一个知识,在Swift开发中,我们经常会看到?
或者!
这样的字符,?
代表可选类型,即该对象可以没有值,!
表示该对象必须有值,在Swift中我们要经常按住option
键去看看一个方法的参数或者返回值是否要必须有值,如下图
那么我们把正确的代码贴出来,分析一下吧
let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
首先,我们看第一个惊叹号,我们从infoDictionary中用key取值,我们要告诉编译器,该字典一定有值,我们才能去取,之后我们把取到的value值强转成了String类型,我们为什么又要在as后面加上一个惊叹号呢,那是因为虽然字典里有值,但是我强转的时候编译器并不确定CFBundleExecutable
这个key的对应的value是否为空,因为用key去取字典中的value使用的是字符串类型,又因为它是字符串,所以这个key是可能写错或者瞎写的,错误的key更不可能取出正确的value值,所以我们在强制转换的时候在as后面加上了惊叹号,表示这个key取出的value是一定有值的,这样我们就拿到了项目的命名空间
PS:在Swift中强制转化用的是as
关键字,并且因为Swift是一门强语言,所以很多错误在还未编译时就提示给你,减少了运行时报错的几率
1.3用途
由于命名空间可以修改,所以项目中单纯的用项目名称代替命名空间的做法并不可靠. 为了满足项目中某些需求,比如:活动期间需要显示与平时完全不同风格的界面,活动结束后又要修改回来,我们不可能在短期连发两个版本,这个就需要跟后台就行互动,将类名提前预留在后台,程序里面使用动态加载类来实现
<a href="http://blog.csdn.net/A1008611789/article/details/50735108">原文链接</a>(侵权删)
//1.动态获取命名空间
let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
//2.将字符串转为类,其中firstTestControllerName完全可以是后台返回给我们的该类的名称,然后去动态创建
let cls : AnyClass? = NSClassFromString(ns + "." + firstTestControllerName)
//将AnyClass转换为指定类型
let vcCls = cls as! UIViewController.Type
//3.通过类创建一个对象
let vc = vcCls.init()
1.4 Swift中导入第三方框架
上面介绍了,OC中没有命名空间的概念,所以我们导入第三方框架的时候,可以将该框架直接拖入工程,进行使用,但是Swift中有了命名空间的概念,所以直接拖入工程会有些问题,我们需要创建一个桥接的主头文件,因为Swift和OC可以混编,所以很多的OC实现的框架也是可以使用的,例如众所周知的AFNetWorking,如下图
但是这样我们还是不能使用的,还要进行如下操作
1.4.1 Swift中使用cocoapods
虽然手动导入后可以使用第三方框架的东西了.但是你们有没有觉得还是很麻烦,又要创建.h文件,又要去build setting中搞一搞,所以Swift中最好还是使用cocoapods导入第三方的框架,这样你导入的文件就会在同一个命名空间下,省去很多苦恼,但是注意一点,在Swift中使用cocoapods,需要在Podfile最前面加上一句话,use_frameworks!
如下图
导入成功后,在需要的地方导入即可
那么现在就是见证奇迹的时刻,既然导入了咱们就使用下吧,比如初始化一个对象
AFHTTPSessionManager.init()
,我们按住cmdmand
键点AFHTTPSessionManager
击跳进去看看里面,如下图
所有的OC代码全部编译成了Swift的代码,所以说cocoapods导入第三方框架是非常适合Swift开发的
总结
今天给大家介绍了Swift的命名空间以及第三方框架的导入,如果有错误的地方请大家多多指正
我是iOS开发的小菜鸡,希望有天可以变成雄鹰
旅途很长,还需修行