Swift & the Objective-C Runtime
Swift & the Objective-C RuntimeWritten byNate Cook—January 26th,2015Even when written without a single line of Objective-C code,every Swift app executes inside the Objective-C runtime,opening up a world of dynamic dispatch and associated runtime manipulation. To be sure,this may not always be the case—Swift-only frameworks,whenever they come,may lead to a Swift-only runtime. But as long as the Objective-C runtime is with us,let’s use it to its fullest potential. This week we take a new,Swift-focused look at two runtime techniques covered on NSHipster back when Objective-C was the only game in town:associated objectsandmethod swizzling.
Associated ObjectsSwift extensions allow for great flexibility in adding to the functionality of existing Cocoa classes,but they’re limited in the same way as their Objective-C brethren,categories. Namely,you can’t add a property to an existing class via an extension. Happily,Objective-Cassociated objectscome to the rescue. For example,to add a extension UIViewController { private struct AssociatedKeys { static var DescriptiveName = "nsh_DescriptiveName" } descriptiveName: String? { get { return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String } set { if let newValue = newValue { objc_setAssociatedObject( &DescriptiveName, newValue as NSString?, .OBJC_ASSOCIATION_RETAIN_NONATOMIC ) } } } }
Method SwizzlingSometimes for convenience,sometimes to work around a bug in a framework,or sometimes because there’s just no other way,you need to modify the behavior of an existing class’s methods. Method swizzling lets you swap the implementations of two methods,essentially overriding an existing method with your own while keeping the original around. In this example,we swizzle public override class func initialize() {
Static {
token: dispatch_once_t = 0
}
// make sure this isn't a subclass
if self !== UIViewController.self {
return
}
dispatch_once(&Static.token) {
originalSelector = Selector("viewWillAppear:")
swizzledSelector = "nsh_viewWillAppear:")
originalMethod = class_getInstanceMethod(originalSelector)
swizzledMethod = swizzledSelector)
didAddMethod = class_addMethod(originalSelector,210)">method_getImplementation(swizzledMethod),210)">method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(swizzledSelector,210)">originalMethod),210)">originalMethod))
} else {
method_exchangeImplementations(originalMethod,210)">swizzledMethod);
}
}
}
// MARK: - Method Swizzling
nsh_viewWillAppear(animated: Bool) {
self.animated)
name = descriptiveName {
print("viewWillAppear: (name)")
} else {
"viewWillAppear: (self)")
}
}
}
load vs. initialize (Swift Edition)The Objective-C runtime typically calls two class methods automatically when loading and initializing classes in your app’s process: Unfortunately,a
In closing,remember that tinkering with the Objective-C runtime should be much more of a last resort than a place to start. Modifying the frameworks that your code is based upon,as well as any third-party code you run,is a quick way to destabilize the whole stack. Tread softly! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |