如果我想为自己分配一个属性怎么办? [英] What if I want to assign a property to itself?

查看:21
本文介绍了如果我想为自己分配一个属性怎么办?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我尝试运行以下代码:

If I attempt to run the following code:

photographer = photographer

我收到错误:

将属性分配给自身.

<小时>

我想将属性分配给自身以强制 photographer didSet 块运行.

这是一个真实的例子:在 2013年冬季斯坦福iOS课程(13:20),教授推荐写类似下面的代码:

Here's a real-life example: In the "16. Segues and Text Fields" lecture of the Winter 2013 Stanford iOS course (13:20), the professor recommends writing code similar to the following:

@IBOutlet weak var photographerLabel: UILabel!

var photographer: Photographer? {
    didSet {
        self.title = photographer.name
        if isViewLoaded() { reload() }
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    reload()
}

func reload() {
    photographerLabel.text = photographer.name
}

注意:我做了以下更改:(1) 代码从 Objective-C 切换到 Swift;(2)因为是在Swift中,所以我使用了属性的didSet块而不是setPhotographer:方法;(3) 而不是 self.view.window 我使用的是 isViewLoaded 因为前者错误地强制视图在访问 view 属性时加载;(4) reload() 方法(仅)为了简单起见更新标签,并且因为它更类似于我的代码;(5) 增加了摄影师IBOutlet标签来支持这个更简单的代码;(6) 由于我使用的是 Swift,isViewLoaded() 检查不再仅仅出于性能原因而存在,现在 需要 来防止崩溃,因为 IBOutlet 是定义为 UILabel! 而不是 UILabel? 所以在加载视图之前尝试访问它会使应用程序崩溃;这在 Objective-C 中不是强制性的,因为它使用空对象模式.

Note: I made the following changes: (1) the code was switched from Objective-C to Swift; (2) because it's in Swift, I use the didSet block of the property instead of the setPhotographer: method; (3) instead of self.view.window I am using isViewLoaded because the former erroneously forces the view to load upon access of the view property; (4) the reload() method (only) updates a label for simplicity purposes, and because it resembles my code more closely; (5) the photographer IBOutlet label was added to support this simpler code; (6) since I'm using Swift, the isViewLoaded() check no longer exists simply for performance reasons, it is now required to prevent a crash, since the IBOutlet is defined as UILabel! and not UILabel? so attempting to access it before the view is loaded will crash the application; this wasn't mandatory in Objective-C since it uses the null object pattern.

我们两次调用 reload 的原因是因为我们不知道是在视图创建之前还是之后设置属性.例如,用户可能先设置属性,然后呈现视图控制器,或者他们可能呈现视图控制器,然后更新属性.

The reason we call reload twice is because we don't know if the property will be set before or after the view is created. For example, the user might first set the property, then present the view controller, or they might present the view controller, and then update the property.

我喜欢这个属性与视图何时加载无关(最好不要对视图加载时间做任何假设),所以我想在我自己的代码中使用相同的模式(仅稍作修改):

I like how this property is agnostic as to when the view is loaded (it's best not to make any assumptions about view loading time), so I want to use this same pattern (only slightly modified) in my own code:

@IBOutlet weak var photographerLabel: UILabel?

var photographer: Photographer? {
    didSet {
        photographerLabel?.text = photographer.name
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    photographer = photographer
}

这里不是创建一个从两个地方调用的新方法,我只想要 didSet 块中的代码.我希望 viewDidLoad 强制调用 didSet,所以我将属性分配给它自己.但是,Swift 不允许我这样做.如何强制调用 didSet?

Here instead of creating a new method to be called from two places, I just want the code in the didSet block. I want viewDidLoad to force the didSet to be called, so I assign the property to itself. Swift doesn't allow me to do that, though. How can I force the didSet to be called?

推荐答案

Swift 3.1 之前,您可以使用以下命令将 name 属性分配给自身:

Prior to Swift 3.1 you could assign the property name to itself with:

name = (name)

但这现在给出了同样的错误:为自己分配一个属性".

but this now gives the same error: "assigning a property to itself".

有许多其他方法可以解决此问题,包括引入临时变量:

There are many other ways to work around this including introducing a temporary variable:

let temp = name
name = temp

这太有趣了,不能分享.我相信社区可以想出更多方法来做到这一点,越疯狂越好

This is just too fun not to be shared. I'm sure the community can come up with many more ways to do this, the crazier the better

class Test: NSObject {
    var name: String? {
        didSet {
            print("It was set")
        }
    }

    func testit() {
        // name = (name)    // No longer works with Swift 3.1 (bug SR-4464)
        // (name) = name    // No longer works with Swift 3.1
        // (name) = (name)  // No longer works with Swift 3.1
        (name = name)
        name = [name][0]
        name = [name].last!
        name = [name].first!
        name = [1:name][1]!
        name = name ?? nil
        name = nil ?? name
        name = name ?? name
        name = {name}()
        name = Optional(name)!
        name = ImplicitlyUnwrappedOptional(name)
        name = true ? name : name
        name = false ? name : name
        let temp = name; name = temp
        name = name as Any as? String
        name = (name,0).0
        name = (0,name).1
        setValue(name, forKey: "name") // requires class derive from NSObject
        name = Unmanaged.passUnretained(self).takeUnretainedValue().name
        name = unsafeBitCast(name, to: type(of: name))
        name = unsafeDowncast(self, to: type(of: self)).name
        perform(#selector(setter:name), with: name) // requires class derive from NSObject
        name = (self as Test).name
        unsafeBitCast(dlsym(dlopen("/usr/lib/libobjc.A.dylib",RTLD_NOW),"objc_msgSend"),to:(@convention(c)(Any?,Selector!,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
        unsafeBitCast(class_getMethodImplementation(type(of: self), #selector(setter:name)), to:(@convention(c)(Any?,Selector!,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
        unsafeBitCast(method(for: #selector(setter:name)),to:(@convention(c)(Any?,Selector,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject 
        _ = UnsafeMutablePointer(&name)
        _ = UnsafeMutableRawPointer(&name)
        _ = UnsafeMutableBufferPointer(start: &name, count: 1)
        withUnsafePointer(to: &name) { name = $0.pointee }

        //Using NSInvocation, requires class derive from NSObject
        let invocation : NSObject = unsafeBitCast(method_getImplementation(class_getClassMethod(NSClassFromString("NSInvocation"), NSSelectorFromString("invocationWithMethodSignature:"))),to:(@convention(c)(AnyClass?,Selector,Any?)->Any).self)(NSClassFromString("NSInvocation"),NSSelectorFromString("invocationWithMethodSignature:"),unsafeBitCast(method(for: NSSelectorFromString("methodSignatureForSelector:"))!,to:(@convention(c)(Any?,Selector,Selector)->Any).self)(self,NSSelectorFromString("methodSignatureForSelector:"),#selector(setter:name))) as! NSObject
        unsafeBitCast(class_getMethodImplementation(NSClassFromString("NSInvocation"), NSSelectorFromString("setSelector:")),to:(@convention(c)(Any,Selector,Selector)->Void).self)(invocation,NSSelectorFromString("setSelector:"),#selector(setter:name))
        var localVarName = name
        withUnsafePointer(to: &localVarName) { unsafeBitCast(class_getMethodImplementation(NSClassFromString("NSInvocation"), NSSelectorFromString("setArgument:atIndex:")),to:(@convention(c)(Any,Selector,OpaquePointer,NSInteger)->Void).self)(invocation,NSSelectorFromString("setArgument:atIndex:"), OpaquePointer($0),2) }
        invocation.perform(NSSelectorFromString("invokeWithTarget:"), with: self)
    }
}

let test = Test()
test.testit()

这篇关于如果我想为自己分配一个属性怎么办?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆