是否可以在Swift中在运行时向对象添加变量?

时间:2014-08-18 17:26:57

标签: swift

具体来说,我想将一个enum类型的变量添加到UIView的实例中,而不进行子类化或创建扩展。

感谢。

4 个答案:

答案 0 :(得分:9)

以下是源自jckarter's answer的简单但完整的示例。

它显示了如何向现有类添加新属性。它通过在扩展块中定义计算属性来实现。 computed属性存储为关联对象:

import ObjectiveC

// Declare a global var to produce a unique address as the assoc object handle
var AssociatedObjectHandle: UInt8 = 0

extension MyClass {
    var stringProperty:String {
        get {
            return objc_getAssociatedObject(self, &AssociatedObjectHandle) as String
        }
        set {
            objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
        }
    }
}

答案 1 :(得分:4)

关于objc_setAssociatedObject()的上一个答案是正确的方法,但我认为Apple的API还没有经过审查,因为我认为它们应该是这样的,因为我很难使用它们用过的。 (我不应该使用不安全的指针等等。)以下是我现在使用的解决方案。

首先,你需要一点Objective-C胶水(按照Apple的说明在同一个项目中混合使用Objective-C和Swift:

// RuntimeGlue.h
// Should be included from your bridging header.

@import Foundation;

void setAssociatedObject_glue(NSObject *object, const NSString *key, NSObject *value);
NSObject *getAssociatedObject_glue(NSObject *object, const NSString* key);


// RuntimeGlue.m

#import "RuntimeGlue.h"
#import <objc/runtime.h>

void setAssociatedObject_glue(NSObject *object, const NSString *key, NSObject *value) {
    objc_setAssociatedObject(object, (__bridge const void *)(key), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

NSObject *getAssociatedObject_glue(NSObject *object, const NSString* key) {
    return objc_getAssociatedObject(object, (__bridge const void *)(key));
}

接下来,您将从程序的其余部分调用Swift方法:

// Runtime.swift

import Foundation

public func setAssociatedObject(#object: NSObject, #key: NSString, #value: NSObject?) {
    setAssociatedObject_glue(object, key, value)
}

public func getAssociatedObject(#object: NSObject, #key: NSString) -> NSObject? {
    return getAssociatedObject_glue(object, key)
}

最后,用于将特定视图控制器的视图标记为&#34; debugging&#34;。

的示例
// MyViewController.swift

import UIKit

let debugKey: NSString = "DebugKey"

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        setAssociatedObject(object: self.view, key: debugKey, value: "debugging")
    }

    override func viewWillAppear(animated: Bool)  {
        super.viewWillAppear(animated)

        let val = getAssociatedObject(object: self.view, key: debugKey)
        println("val:\(val)")
    }
}

此方法允许您将nil value传递给setter,以清除键的值,并从getter返回一个可选项。另请注意,key参数在两种情况下必须相同(k1 === k2),而不仅仅等效(k1 == k2)。

另请注意,这只允许您标记NSObject或其子类的实例 - 它不适用于Swift本机类。 value也必须是NSObject子类,但字符串和数字文字都自动桥接到Objective-C,因此您不需要进行任何显式转换。

答案 2 :(得分:1)

您可以使用Objective-C运行时的objc_setAssociatedObject()函数将对象(您可以将该枚举包装到对象中)附加到另一个对象上,并objc_getAssociatedObject()来检索它。

答案 3 :(得分:0)

objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC