我正在尝试向UIViewController添加其他属性。
代码:
protocol AdditionalStoredProperties
{
associatedtype Title
func getAssociatedObject<Title>(key: UnsafePointer<Title> ,
defValue : Title)->Title
}
extension AdditionalStoredProperties
{
func getAssociatedObject<Title>( key: UnsafePointer<Title> , defValue : Title)->Title
{
guard let actual_value = objc_getAssociatedObject(self as! AnyObject, key) as? Title else
{
return defValue
}
return actual_value
}
}
extension UIViewController:AdditionalStoredProperties
{
typealias Title = String
var previousPage : String
{
get { return getAssociatedObject(&self.previousPage, defValue: self.previousPage) }
set { objc_setAssociatedObject(self, &self.previousPage, newValue, .OBJC_ASSOCIATION_RETAIN)}
}
}
但是我收到以下错误:
错误:尝试将堆栈放在不可读的内存中:
我知道我们无法直接将存储的属性添加到扩展中,因此我尝试使用objc_setAssociatedObject()
进行添加答案 0 :(得分:5)
你正在做的事情有很多问题:
尝试在自己的getter中访问self.previousPage
将以递归方式调用自身。
您不能将&self.previousPage
用作稳定或唯一的指针值,因为它将是指向临时变量的指针(因为您正在处理计算属性)。因此,您不能将其用作关联对象的键。 Swift只为保证静态和全局存储变量的稳定且唯一的指针值(有关详细信息,请参阅this Q&A)。
您应该使AdditionalStoredProperties
成为一个类绑定协议(使用: class
),因为您只能将关联对象添加到Objective-C类(在Apple平台上,Swift类是建在上面)。虽然你可以桥接,例如,struct
到AnyObject
(它将被封装在一个不透明的Obj-C兼容包装器中),但它只是那个;一个桥。无法保证您将获得相同的实例,因此无法保证相关对象将保持不变。
您可能并不认为Title
是您协议的关联类型;您没有将它用于任何事情(Title
定义的通用占位符getAssociatedObject(key:defValue:)
完全不相关。)
请记住这些要点,这是您的代码的固定版本:
protocol AdditionalStoredProperties : class {
func getAssociatedObject<T>(ofType: T.Type, key: UnsafeRawPointer,
defaultValue: @autoclosure () -> T) -> T
}
extension AdditionalStoredProperties {
func getAssociatedObject<T>(ofType: T.Type, key: UnsafeRawPointer,
defaultValue: @autoclosure () -> T) -> T {
// or: return objc_getAssociatedObject(self, key) as? T ?? defaultValue()
guard let actualValue = objc_getAssociatedObject(self, key) as? T else {
return defaultValue()
}
return actualValue
}
}
extension UIViewController : AdditionalStoredProperties {
private enum AssociatedObjectKeys {
static var previousPage: Never?
}
var previousPage: String {
get {
// return the associated object with a default of "" (feel free to change)
return getAssociatedObject(ofType: String.self,
key: &AssociatedObjectKeys.previousPage,
defaultValue: "")
}
set {
objc_setAssociatedObject(self, &AssociatedObjectKeys.previousPage,
newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}
请注意,我们是:
使用static
存储的属性以获取指针值以用作关联对象的键。同样,这可行,因为Swift guarantees stable and unique pointer values for static and global stored variables。
使用@autoclosure
作为defaultValue:
参数,因为如果关联对象已经存在,则可能无需进行评估。
让key:
参数取UnsafeRawPointer
,因为指针对象的类型无关紧要;它只是内存中用作密钥的位置。
使用ofType:
参数明确满足通用占位符。这主要是一个偏好问题,但我更愿意明确地拼写这些内容,而不是依赖于类型推断。
使用camelCase
代替snake_case
,与Swift惯例一样。
答案 1 :(得分:3)
如果有人遇到以下情况
如果递归调用方法,则可能会出现此错误。