2015-04-21 52 views
0

我在我的NSManagedObject上使用了一些Transient屬性來預先計算只需要在依賴屬性更新時計算一次的事情,但是當我重置Transient屬性時永遠不會保存的值。setPrimitiveValue for Transient property not saved

例如:

-(NSString*)age { 
    // notify core data to access value 
    [self willAccessValueForKey:@"age"]; 
    // get primitive value 
    NSString* age = [self primitiveValueForKey:@"age"]; 
    // is age already exist? 
    if (age == nil) { 
     // get age 
     age = [GlobalHelper convertToAgeStringWithUTCDateOfBirth:(NSString*)self.dateOfBirth]; 
     // set primitive value 
     [self setPrimitiveValue:age forKey:@"age"]; 
    } 
    // notify core data done access value 
    [self didAccessValueForKey:@"age"]; 
    return age; 
} 

-(void)setDateOfBirth:(id)dateOfBirth { 
     // change value for key 
     [self willChangeValueForKey:@"dateOfBirth"]; 
     [self willChangeValueForKey:@"age"]; 
     // set primitive 
     [self setPrimitiveValue:dateOfBirth forKey:@"dateOfBirth"]; 
     [self setPrimitiveValue:nil forKey:@"age"]; 
     // did change value for key 
     [self didChangeValueForKey:@"age"]; 
     [self didChangeValueForKey:@"dateOfBirth"]; 
} 

所以你可以從上面的代碼中看到,當我同步此對象,當「出生日期」字段更新它嘗試設置「年齡」爲「零」,當訪問「年齡」字段,如果它是「無」,那麼計算年齡並不再計算它。

然而,問題是當我在「setDateOfBirth」中將「age」字段設置爲「nil」時,它從來沒有保存過,當我再次訪問年齡時,「age」屬性仍然具有以前的值,但「dateOfBirth」已更新。

任何遠程與此主題有關的幫助將是非常讚賞,我有這個大麻煩......

編輯:我上面有邏輯的作品完美的方案,其中從相同的兩個setter和getter電話上下文(相同的線程上下文),問題只發生在setter從具有專用隊列的AFNetworking API的完成塊中調用並且合併後從主線程調用的getter時。

看來,當我從AFNetworking完成塊的上下文中保存時,它只保存dateOfBirth,但不保存dateOfBirth,它在合併後設置爲零,並且當來自主線程「age」的getter調用具有先前的值時它永遠不會再計算。

+0

你剛纔說年齡是一個短暫的財產,你爲什麼期望它被保存? – Rog

+0

瞬態屬性不會保存到存儲器中,但會保存到內存上下文中,並且可以在https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes中很好地解釋瞬態屬性的用途。 html – andykkt

+1

您需要在保存這些記錄的位置發佈代碼的一部分。它可能是一個管理對象上下文跨越線程的問題,或者將更改與瞬態屬性合併(詳見本頁底部的詳細信息)https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles /cdUsingMOs.html) – Rog

回答

1

你不應該在閱讀年齡時設置年齡。這似乎是非常奇怪的設計,也沒有調用適當的鍵值編碼通知。

請按照您的原始邏輯:如果出生日期發生變化,請更新年齡。您應該在setDateOfBirth中執行此操作,並在設置器中調用適當的鍵值編碼通知age

-(void) setDateOfBirth:(id)newValue { 
    [self willChangeValueForKey:@"dateOfBirth"]; 
    [self setPrimitiveValue:newValue forKey:@"dateOfBirth"]; 
    [self didChangeValueForKey:@"dateOfBirth"]; 

    self.age = [GlobalHelper 
     convertToAgeStringWithUTCDateOfBirth:(NSString*)newValue]; 
} 

-(void)age { 
    [self willAccessValueForKey:@"age"]; 
    NSString* age = [self primitiveValueForKey:@"age"]; 
    [self didAccessValueForKey:@"age"]; 
    if (age == nil) { 
     age = [GlobalHelper 
     convertToAgeStringWithUTCDateOfBirth:(NSString*)self.dateOfBirth]; 
    } 
    self.age = age; 
    return age; 
} 

然而,所有你不得不問自己多麼昂貴的convertAge電話真的是。除了最極端的情況外,其中一個簡單的獲取器實際上就是您所需要的。

此外,我認爲你的dateOfBirth屬性應該有一個標準的管理對象屬性類型,而不是id。它是一個字符串嗎?那麼你應該聲明它爲NSString,而不是使用id和演員。

+0

首先,謝謝你的答案和原因dateOfBirth屬性是id,因爲它是Transformer類型,它是爲了安全原因而編碼的,但與此無關..我在dateOfBirth屬性設置並計算它時重置了年齡的原因只要年齡爲零,我就可以確保它只計算一次。並且它對於一個轉換API調用來說並不昂貴,但想象一下,如果您需要在表視圖中顯示數百或數千個字段,並且每次滾動它時都會調用convert api。 – andykkt

+0

我得到的邏輯完美適用於場景從相同的上下文(相同的線程上下文)的setter和getter調用,問題只發生在AFNetworking api的完成塊從private線程調用的setter和合並後從主線程調用的getter時。 – andykkt

+0

如果你只是使用一個getter,即使在一個有1000個條目的tableview中,它也只會被屏幕上的行調用,所以沒問題。 - 至於線程問題,您應該將更改傳遞給主線程(例如,通過保存父上下文)並保存。 – Mundi