2017-08-07 23 views
4

我想向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

你在做什麼有幾個錯誤:

  • 試圖在自己的getter中訪問self.previousPage將自動遞歸調用自身。

  • 不能使用&self.previousPage爲穩定或唯一指針的值,因爲這將是一個指向一個臨時變量(因爲你處理一個計算的屬性)。因此,您不能將其用作關聯對象的關鍵字。僅限Swift 保證靜態和全局存儲變量的穩定和唯一指針值(有關更多信息,請參閱this Q&A)。因爲只能將關聯對象添加到Objective-C類(在Apple平臺上,Swift類基於此構建),因此您應該使AdditionalStoredProperties成爲類綁定協議(使用: class)。雖然你可以橋接,例如,一個structAnyObject(它會被裝在一個不透明的Obj-C兼容包裝盒中),但它僅僅是這樣;一個。不能保證你會得到相同的實例,因此不能保證關聯的對象會持續存在。

  • 您可能並不是指Title是您協議的關聯類型;你沒有使用它的任何東西(由getAssociatedObject(key:defValue:)定義的通用佔位符Title是完全無關的)。

銘記那些點,這裏是你的代碼的固定版本:

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,因爲如果關聯的對象已經存在,則可能不需要評估它。

  • 參照key:參數取UnsafeRawPointer,因爲指針的類型是不相關的;它僅僅是用作密鑰的內存中的位置。

  • ofType:參數明確地滿足通用佔位符。這主要是一個偏好問題,但我更願意明確地將這些事情拼出來,而不是依靠類型推斷。

  • 使用camelCase而不是snake_case,因爲是Swift約定。

+0

謝謝你的寶貴意見,並指出我到底出錯的地方。我應該注意到遞歸調用self的錯誤。 – user2879160

+0

@ user2879160樂意幫忙! :) – Hamish