2016-01-07 35 views
1

我有各種屬性的swift類,其中一些屬性具有可選類型。無法在Swift中將自定義設置爲無可選屬性

class UserObject: PFUser{ 

    //optional property 
    var optionalPhotoURL:String? { 
     get { 
      if let optionalPhotoURL:String = objectForKey("optionalPhotoURL"){ 
       return optionalPhotoURL 
      } 
      //not needed but just for emphasis 
      return nil 
     } 

     //I am unable to set UserObject.optionalPhotoURL = nil with this setters 
     set { 
      if let newPhotoURL:String = newValue! { 
       setObject(newPhotoURL, forKey: "optionalPhotoURL") 
      }else{ 
      self.optionalPhotoURL = nil 
      } 
     } 
    } 
} 

我無法設置optionalPhotoURL爲零,如果它已經有一個先前的值分配給它。

我想我的問題是,我如何「取消」與自定義setter的可選屬性?

更新

這些制定者都崩潰

set { 
     if let newPhotoURL:String = newValue { 
      setObject(newPhotoURL, forKey: "optionalPhotoURL") 
     }else{ 
     self.optionalPhotoURL = nil 
     } 
    } 

set { 
     if (newValue != nil) { 
      setObject(newValue!, forKey: "optionalPhotoURL") 
     }else{ 
      self.optionalPhotoURL = nil 
     } 
    } 
+0

你確定它會進入else語句嗎? – lascort

+0

newValue是swift如何調用正在設置的newValue,除非命名var被定義爲set(somevar){} – stone

+0

依賴'setObject(forKey :)'有很多問題...... – nhgrif

回答

4

你在這裏有一個計算財產。

Swift屬性可以被計算或存儲。我們可以通過使用didSetwillSet來觀察我們存儲的屬性中的值更改,但這裏我們仍然有一個存儲屬性。

對於您的情況,由於您已覆蓋setget*,您沒有存儲屬性,因此您有計算屬性。如果您希望計算屬性具有後備存儲,則必須獨立創建。

所以,你可能想是這樣的:

class FooClass { 
    private var storageProperty: String? 
    var accessProperty: String? { 
     get { 
      return self.storageProperty 
     } 
     set { 
      self.storageProperty = newValue 
      // or whatever logic you may like here 
     } 
    } 
} 

*:還沒有覆蓋get不能覆蓋set。但是,您可以覆蓋get而不會覆蓋set - 這將生成只讀計算值。


此外,我們以這種方式實現我們的存儲屬性非常重要,因爲它依賴於鍵值編碼。

對於初學者,setObject(forKey:)方法甚至不能在純Swift類型上工作。這隻適用於從Objective-C類型繼承的對象。它是從NSObject遵守NSKeyValueCoding協議的繼承方法。爲什麼Objective-C的基礎對象符合如此多的協議是超越我的......但它確實如此,我們無能爲力。

如果我們有一些代碼庫,其中一些對象繼承自Objective-C對象(基本上任何項目都有,UIViewController等),而我們的一些對象是純Swift對象(您將傾向於當你從頭開始創建你自己的Swift類時),那麼我們的Swift對象將無法實現這種相同的模式。如果我們有兩種類型的對象,我們要麼必須實現上面顯示的所有模式(然後我們有一致性),要麼我們必須爲某些類型實現一個模式,而爲其他類型實現另一個模式( Swift結構肯定會實現上面的模式,你不能讓它們繼承自NSObject)(然後我們有不一致性,我們不喜歡它)。

setObject(forKey:)更糟的是,這種方法的第一個參數總是類型AnyObject。根本沒有類型安全性。通過setObject(forKey:)存儲的地方完全基於我們使用的密鑰。當我們使用setObject(forKey:)時,我們採用了Swift給我們的一堆類型安全優勢,並將它們扔出窗外。如果我們不關心利用Swift爲Objective-C提供的優勢,那我們爲什麼要用Swift編寫它?

當我們使用setObject(forKey:)時,我們甚至不能使存儲的財產私人。任何知道密鑰的人都可以撥打setObject(forKey:)並將該對象設置爲任何他們想要的。這包括不是字符串的對象。我們所要做的將這個代碼庫引入崩潰的方法是編寫一個類擴展或子類,它與您使用的其他類型(對於同一個鍵也許是一個NSData值)之間存在關鍵衝突。即使它不是一種不同的類型,只需爲多個屬性複製相同的密鑰就會引入錯誤以及難以調試的錯誤。

2

切勿自稱設置一個計算屬性的值,在其set範圍!
這會導致無限循環並且應用程序會崩潰。

我不知道哪個API setObject:forKey屬於,但在nil的情況下,你都應該刪除對象

set { 
    if let newPhotoURL = newValue { 
     setObject(newPhotoURL, forKey: "optionalPhotoURL") 
    } else { 
     removeObjectForKey("optionalPhotoURL") 
    } 
} 
+0

完美。經過測試和工作! – stone

+1

依靠'setObject(forKey :)'有很多問題...... – nhgrif

+0

這與問題無關@nhgrif – vadian

相關問題