项目中根据类名创建类,在实际项目中用处还是挺多的。举个简单的例子,下面是支付宝的个人中心界面
支付宝个人中心
点击每个cell进入不同的试图控制器,常见的写法就是根据indexPath去判断,if else if添加判断。这样的代码质量不高,而且还有#import很多其他的控制器,相对而言在OC中可以根据类名动态的创建视图控制器,
UIViewController *baseVC = [[NSClassFromString(className) alloc]initWithNibName:className bundle:nil];
[self.navigationController pushViewController:baseVC animated:YES];
在个人中心视图中创建一个试图控制器的数组,根据地点的cell的indexPath获取到对应的试图控制器的类名(他们有统一的一个基类),我们可以通过Class类型就可以调用alloc来分配内存,调用init方法来初始化。
在swift中这样的方法就不行了,因为一看到Swift中NSClassFromString返回的是AnyClass类型,而这个AnyClass类型为public typealias AnyClass = AnyObject.Type,这个Type具体是什么呢?为什么option+点击进不去,无法查看呢?AnyObject其实只是一个空协议,难道.Type是自动有的吗?这个本人也不清楚。 className的类型是UIViewController.type看来我们用这种方式在swift中是不行了,获取的只是一个type类型的类,在swift中想过类名去动态创建类,我们还需要知道命名空间
这个东西😂😂😂。
Objective-C一直以来令人诟病的地方就是没有命名空间,在应用开发时,所有的代码和引用的静态库最终都会被编译到同一个域和二进制中。这样的后果是一旦我们有重复的类名的话,就会导致编译出错和冲突。为了避免这种情况,Objective-C的类型一般都会加上两到三个字母的前缀,比如Apple保留的NS和UI前缀,各个系统框架的前缀SK(StoreKit),CG(CoreGraphic)等。Objective-C社区的大部分开发者也遵循这个约定,一般都会将自己的名字作为前缀,把类库命名为AFNetworking或者MBProgressHUD这样,这种做法可以解决部分问题,至少我们在直接引用不同人的库时冲突的概率大大降低了,但是前缀并不意味着不会冲突,有时候我们确实还是会遇到即使使用前缀也仍然相同的情况。另外一种情况是可能你想使用的两个不同的库,分别在它们里面引用了另一个相同的很流行的第三方库,而又没有更改名字。在你分别使用这两个库中的一个时是没有问题的,但是一旦你将这两个库同时加到你的项目中的话,这个大家共用的第三方库就会和自己发生冲突了。
在 Swift 中,由于可以使用命名空间了,即使是名字相同的类型,只要是来自不同的命名空间的话,都是可以和平共处的。和 C# 这样的显式在文件中指定命名空间的做法不同,Swift 的命名空间是基于 module 而不是在代码中显式地指明,每个 module 代表了 Swift 中的一个命名空间。也就是说,同一个 target 里的类型名称还是不能相同的。在我们进行 app 开发时,默认添加到 app 的主 target 的内容都是处于同一个命名空间中的,这个target的默认模块名称就是这个项目的名称(可以在target的Build Settings—Product Module Name配置)图中红框中的就是项目工程名(这是swift默认的) Swift中的命名空间注意点
1:不同项目中的命名空间是不一样的, 默认情况下命名空间的名称就是当前项目的名称
2:因为Swift可以通过命名空间来解决重名的问题,所以在做Swift开发时尽量使用cocoapods来集成三方框架,这样可以有效的避免类名重复
3:因为Swift中有命名空间,所以通过一个字符串来创建一个类和OC中也不太一样了, OC中可以直接通过类名创建一个类,而Swift中如果想通过类名来创建一个类必须加上命名空间。
下面我们采用swift的命名空间,动态的去创建并实例化一个类
//1:动态获取命名空间
guard let spaceName = Bundle.main.infoDictionary!["CFBundleExecutable"] as? String else {
print("获取命名空间失败")
return
}
let vcClass: AnyClass? = NSClassFromString(nameSpace + "." + name) //VCName:表示试图控制器的类名
// Swift中如果想通过一个Class来创建一个对象, 必须告诉系统这个Class的确切类型
guard let typeClass = vcClass as? UIViewController.Type else {
print("vcClass不能当做UIViewController")
return
}
let myVC = typeClass.init()
//或者加载xib; let myVC = typeClass.init(nibName: name, bundle: nil)
通过这种方式就可以和Objective-C实现相同的功能了🤣🤣🤣🤣🤣
网友评论