[REWRITTEN after further research]
Here's an elaborate workaround based on the below
http://nshipster.com/swift-objc-runtime/
[WARNING from the authors]
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!
So here it is, all accessors and mutators have to be covered, so it's a lot.
Plus, since you need to intercede with the values but must re-use the original stored property since you can't introduce any new storage here, you have some bizarre looking functions that appear to be recursive but aren't because of runtime swizzling. This is the first time the compiler has generated a warning for my code that I know will be wrong at runtime.
Oh well, it is an interesting academic exercise.
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
}
}
}