[进一步研究后重写]
这是基于以下内容的详细解决方法
http://nshipster.com/swift-objc-runtime/
[来自作者的警告]
最后,请记住,修补 Objective-C 运行时应该是最后的手段,而不是开始的地方。修改您的代码所基于的框架以及您运行的任何第三方代码,是破坏整个堆栈稳定性的一种快速方法。轻踩!
所以在这里,所有的访问器和修改器都必须被覆盖,所以很多。另外,由于您需要对这些值进行调解,但必须重新使用原始存储的属性,因为您不能在这里引入任何新的存储,所以您有一些看起来很奇怪的函数,它们看起来是递归的,但不是因为运行时混乱。这是编译器第一次为我的代码生成警告,我知道在运行时会出错。
哦,好吧,这是一个有趣的学术练习。
extension UIScrollView {
struct StaticVars {
static var token: dispatch_once_t = 0
}
public override class func initialize() {
dispatch_once(&StaticVars.token) {
guard self == UIScrollView.self else {
return
}
// Accessor
method_exchangeImplementations(
class_getInstanceMethod(self, Selector("swizzledContentOffset")),
class_getInstanceMethod(self, Selector("contentOffset"))
)
// Two-param setter
method_exchangeImplementations(
class_getInstanceMethod(self, #selector(UIScrollView.setContentOffset(_:animated:))),
class_getInstanceMethod(self, #selector(UIScrollView.swizzledSetContentOffset(_:animated:)))
)
// One-param setter
method_exchangeImplementations(
class_getInstanceMethod(self, #selector(UIScrollView.swizzledSetContentOffset(_:))),
class_getInstanceMethod(self, Selector("setContentOffset:")))
}
}
func swizzledSetContentOffset(inContentOffset: CGPoint, animated: Bool) {
print("Some interceding code for the swizzled 2-param setter with \(inContentOffset)")
// This is not recursive. The method implementations have been exchanged by runtime. This is the
// original setter that will run.
swizzledSetContentOffset(inContentOffset, animated: animated)
}
func swizzledSetContentOffset(inContentOffset: CGPoint) {
print("Some interceding code for the swizzled 1-param setter with \(inContentOffset)")
swizzledSetContentOffset(inContentOffset) // not recursive
}
var swizzledContentOffset: CGPoint {
get {
print("Some interceding code for the swizzled accessor: \(swizzledContentOffset)") // false warning
return swizzledContentOffset // not recursive, false warning
}
}
}