错误:尝试将堆栈放在不可读的内存中:

时间:2017-08-07 07:33:51

标签: swift

我正在尝试向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()

进行添加

2 个答案:

答案 0 :(得分:5)

你正在做的事情有很多问题:

  • 尝试在自己的getter中访问self.previousPage将以递归方式调用自身。

  • 您不能将&self.previousPage用作稳定或唯一的指针值,因为它将是指向临时变量的指针(因为您正在处理计算属性)。因此,您不能将其用作关联对象的键。 Swift只为保证静态和全局存储变量的稳定且唯一的指针值(有关详细信息,请参阅this Q&A)。

  • 您应该使AdditionalStoredProperties成为一个类绑定协议(使用: class),因为您只能将关联对象添加到Objective-C类(在Apple平台上,Swift类是建在上面)。虽然你可以桥接,例如,structAnyObject(它将被封装在一个不透明的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)

如果有人遇到以下情况

如果递归调用方法,则可能会出现此错误。