Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/100.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios swift中属性的方法swizzling_Ios_Swift_Selector_Objective C Runtime_Method Swizzling - Fatal编程技术网

Ios swift中属性的方法swizzling

Ios swift中属性的方法swizzling,ios,swift,selector,objective-c-runtime,method-swizzling,Ios,Swift,Selector,Objective C Runtime,Method Swizzling,虽然可以替换obj-c中的setMyProperty:方法,但我想知道如何在swift中实现它 例如,我想替换UIScrollView::setContentOffset:: let originalSelector: Selector = #selector(UIScrollView.setContentOffset) let replaceSelector: Selector = #selector(UIScrollView.setContentOffsetHacked) ... …但在执

虽然可以替换obj-c中的
setMyProperty:
方法,但我想知道如何在swift中实现它

例如,我想替换
UIScrollView::setContentOffset:

let originalSelector: Selector = #selector(UIScrollView.setContentOffset)
let replaceSelector: Selector = #selector(UIScrollView.setContentOffsetHacked)
...

…但在执行后,
originalSelector
包含
setContentOffset:animade
。那么,如何将属性的setter方法传递给选择器呢?

[在进一步研究后重写]

下面是一个基于以下内容的详细解决方案

[作者的警告]

最后,请记住修补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
        }
    }
}
从Swift 2.3(XCode 8)开始,可以将setter和getter分配给选择器变量:

属性的getter或setter的Objective-C选择器可以 现在用#选择器引用。例如:


更多详细信息

这篇文章可以帮助您,如果您想抓住兔子洞:@VictorSigler这篇文章不包括property setter的这种特殊情况。@BaseZen,您提到的问题和答案也是如此。我正在研究如何处理属性setter,特别是我想知道为什么从
#selector(UIScrollView.setContentOffset)
中选择了错误的方法。答案已经重做,所以我很好奇这是否符合您的需要。谢谢,但我确实需要为
UIScrollView
及其子类替换
setContentOffset
。原因是-我正在实现自定义拉刷新控件。我在
UIScrollView
接口中看到了
public var contentOffset:CGPoint
,所以它是读写的,而不是只读的
setContentOffset(动画:)
是独立的方法。拖动滚动视图时,其
contentOffset
通过setter设置,而不是通过
setContentOffset:animated
设置。看起来你的答案没有解决我的问题。你是对的,我误解了它在Xcode中是如何显示为“V”的,我认为这意味着只读。重做。无论如何,看看我的新评论。这一切似乎都起作用了。
let sel: Selector = #selector(setter: UIScrollView.contentOffset)