如果我想为其分配属性,该怎么办? [英] What if I want to assign a property to itself?

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

问题描述

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

If I attempt to run the following code:

photographer = photographer

我得到了错误:

为其分配属性.

Assigning a property to itself.


我想为其分配属性,以强制运行photographer didSet块.


I want to assign the property to itself to force the photographer didSet block to run.

这是一个真实的例子:在 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)我使用的是isViewLoaded而不是self.view.window,因为前者错误地强制视图在访问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天全站免登陆