使对象变量成为指向另一个变量的指针

时间:2016-04-03 14:48:59

标签: ios swift

这远远超出了我的编程理解范围,所以非常感谢理解这个概念的任何帮助。

我所拥有的是一个图层类FloaterContainerLayer。

lazy var dotLayer : FloaterContainerLayer = {
        let scrollLayer = FloaterContainerLayer()
        scrollLayer.bounds = self.view.layer.bounds
        scrollLayer.position = CGPoint(x: self.view.bounds.size.width/2, y: self.view.bounds.size.height/2)
        scrollLayer.image = "dot"
        scrollLayer.gravity = dotLayerGravity

        return scrollLayer
    }()

我总是有三个这个班级的实例。其中一个是dotLayer。

var dotLayerGravity: CGFloat {
    get {
        if let stored = userDefaults.objectForKey("dotLayerGravity") {
            return CGFloat(stored as! NSNumber)
        }
        else {
            return 10.0
        }
    }
    set(value) {
        userDefaults.setValue(value, forKey: "dotLayerGravity")
    }
}

在其他地方,我有点图层的重力变量。

dotLayer.gravity

现在,此值可以随时更改。我在视图渲染方法中使用dotLayer.gravity = dotLayerGravity,我每秒调用60次。

我想要完成的是:

我订的时候 dotLayer.gravity

并致电 dotLayerGravity

我希望它返回dotLayerGravity

只是将类中的重力变量设置为{{1}}不是一个选项,因为该类用于三个实例。

我尝试了这个,但它不起作用。 enter image description here

2 个答案:

答案 0 :(得分:3)

使用CGFloat / Float / Double / Int,...作为指针在Swift中是不可能的,因为它们是值类型。一种可能的解决方案是创建一个简单的包装类,它将充当指针。

class CGFloatPointer : FloatLiteralConvertible {

    var value : CGFloat = 0

    required convenience init(floatLiteral value: Float) {
        self.init()
        self.value = CGFloat(value)
    }
}

您可以使用FloatLiteralConvertible之类的内容扩展此类,以便于使用。

var gravity:CGFloatPointer = 5.0

这比UnsafePointer更容易维护。

一个小细节。从您的解释中可以看出,您将要从/向UserDefaults加载/保存很多。这很糟糕,因为它很慢。

对于你的代码,我会推荐一些介于全局变量和单例之间的东西,并抛出一些额外的魔法来规范读/写操作。

class DotLayerGravity {
    private static var inMemory : CGFloat?
    static var value: CGFloat {
        get {
            if let inMemory = inMemory {
                return inMemory
            } else {
                let fetchedGravity = (NSUserDefaults.standardUserDefaults().objectForKey("dotLayerGravity") as? NSNumber) ?? 10
                inMemory = CGFloat(fetchedGravity)
                return inMemory!
            }
        }
        set(value) {
            NSUserDefaults.standardUserDefaults().setValue(value, forKey: "dotLayerGravity")
            // setting this to nil will make it fetch from permanenent storage.
            inMemory = nil
        }
    }
}

由于valuestatic属性,因此您可以在应用中的任何位置访问它。这根本不需要,但它确实只保证了这个值的一个实例。

inMemoryprivate,将保留NSUserDefaults的值,直到写入操作完成。 private为班级提供了一个更清晰的界面。

当您获得value的值时,它会首先通过展开inMemory来检查内存中是否有值,如果是nil,它将在NSUserDefaults上回退},当它也是nil时,它将回退到默认值。

它会将获取的或默认值存储在inMemory中并返回最终结果。 这确保了NSUserDefaults的最小读取次数。

这不是线程安全的,但可以是。

重新阅读您的问题,向我明确表示每个实例都将gravity存储在NSUserDefaults中。在这种情况下,我会FloaterContainerLayer通过设置和gravity identifierStringNSUserDefaults充分负责。

class FloaterContainerLayer:CALayer {

    var maxFloaters = 9
    var image:String?
    var velocity:CGFloat = 50.0

    var identifier : String = "floaterContainerIdentifier"

    private var inMemoryGravity : CGFloat?
    var gravity: CGFloat {
        get {
            if let inMemory = inMemoryGravity {
                return inMemory
            } else {
                let fetchedGravity = (NSUserDefaults.standardUserDefaults().objectForKey(identifier) as? NSNumber) ?? 10
                inMemoryGravity = CGFloat(fetchedGravity)
                return inMemoryGravity!
            }
        }
        set(value) {
            NSUserDefaults.standardUserDefaults().setValue(value, forKey: identifier)
            // setting this to nil will make it fetch from permanenent storage.
            inMemoryGravity = nil
        }
    }
}

class SomeViewController : UIViewController {

    lazy var dotLayer : FloaterContainerLayer = {
        let scrollLayer = FloaterContainerLayer()
        scrollLayer.bounds = self.view.layer.bounds
        scrollLayer.position = CGPoint(x: self.view.bounds.size.width/2, y: self.view.bounds.size.height/2)
        scrollLayer.image = "dot"
        scrollLayer.identifier = "dotLayerGravity"

        return scrollLayer
    }()
}

答案 1 :(得分:1)

仅支持功能而不是属性设置引用指针。这意味着您需要一个set方法

var testVariable: CGFloat = 100.0

class Test {
    var testPtr: UnsafePointer<CGFloat>?

    func setTestPtr(ptr: UnsafePointer<CGFloat>) {
        self.testPtr = ptr
    }
}

let t = Test()
t.setTestPtr(&testVariable)

testVariable = 110

let x = t.testPtr?.memory // 110