swift有运行时特性吗?和OC的运行时有区别吗?runtime怎么用呢?Swift的extension(扩展)可以添加方法和属性吗?下面我们来一起回答下这几个问题,并且了解下Swift的特性。
1.swift有运行时特性吗?
Swift 没有运行时特性,它是一门静态语言。这就不合题意了,那我们该怎么介绍 swift runtime呢,莫急,且听我慢慢说....
Swift extensions(扩展) 在给已经存在cocoa系统类添加功能提供了巨大的灵活性,但是和它的OC兄弟一样存在着一样的问题:category的局限性;也就是说你不能通过扩展添加一个属性给已经存在的类,令人庆幸的是,OC的runtime关联属性的方法在解决category的局限性上起了巨大的作用,令人欣慰的是,OC可以和Swift混编,可以互用各自的方法和类,这时就有人会说 swift可以使用OC的runtime的接口吗? 答案是肯定的。我们再来回答第二个问题
2.和OC的运行时有区别吗
除了语法上的区别外,原理都是一样的,Swift是使用OC的runtime接口间接拥有了运行时的特性
3.Swift中runtime怎么用呢?
下面我们来看一个例子
给NSObject 类添加一个 personName的String类型
extension NSObject {
private struct AssociatedKeys {
static var personName = "yf_PersonName"
}
var personName: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.personName) as? String
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.personName,
newValue as NSString?,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
}
需要注意的是,一个私有的结构体中使用 静态变量(static var),此模式创建我们需要的静态关联对象key,但不会弄脏我们的命名空间
Method Swizzling
有时候我们会需要处理一个framework 的bug,或者需要需要修改一个存在的类中的方法,Method Swizzling 可以让你交换两个方法的实现,最厉害的是可以替换一个存在的方法和你自己实现的方法,并且保持原来的运行顺序,现在我们来看一个列子
extension UIViewController {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
// make sure this isn't a subclass
if self !== UIViewController.self {
return
}
dispatch_once(&Static.token) {
let originalSelector = Selector("viewWillAppear:")
let swizzledSelector = Selector("nsh_viewWillAppear:")
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
}
// MARK: - Method Swizzling
func nsh_viewWillAppear(animated: Bool) {
self.nsh_viewWillAppear(animated: animated)
if let name = self.personName {
print("viewWillAppear: \(name)")
} else {
print("viewWillAppear: \(self)")
}
}
这样我们就实现了在每个试图控制器 将要出现是打印 personName 这个属性的目的了,但是不幸的是 override class func initialize,这个再iOS3.0以后,苹果就不建议用了,因为这是OC的方法,不能保证swift以后的版本都会被调用,我们可以在 app delegate(_:didFinishLaunchingWithOptions:),也就是程序启动的时候,去掉用我们替换方法的方法,并且应该保证每次启动都会调用,就可以了
回答最后一个问题
4.Swift的extension(扩展)可以添加方法和属性吗?
局限性和OC的category一样,是不可以的,需要使用runtime的接口来实现