SwiftのNSManagedObject
サブクラスの関係プロパティにオブジェクトを追加するにはどうすればよいですか?
Objective-Cでは、データモデルからXcodeでNSManagedObject
サブクラスを生成すると、次のような宣言を含む自動生成されたクラス拡張があります。
@interface MyManagedObject (CoreDataGeneratedAccessors)
- (void)addMySubObject: (MyRelationshipObject *)value;
- (void)addMySubObjects: (NSSet *)values;
@end
ただし、現在XcodeにはSwiftクラスのこのクラス生成機能がありません。
Swiftオブジェクトで同等のメソッドを直接呼び出してみた場合:
myObject.addSubObject(subObject)
...これらの生成されたアクセサが表示されないため、メソッド呼び出しでコンパイラエラーが発生します。
ドキュメントで説明されているように、リレーションシッププロパティを@NSManaged
として宣言しました。
または、リレーションシップを持つデータモデルのObjective-Cオブジェクトに戻す必要がありますか?
ええ、それはもう動作しません、Swiftはこの方法で実行時にアクセサを生成できません、それは型システムを壊すでしょう。
あなたがしなければならないことは、キーパスを使用することです:
var manyRelation = myObject.valueForKeyPath("subObjects") as NSMutableSet
manyRelation.addObject(subObject)
/* (Not tested) */
Xcode 7およびSwift 2.0( リリースノート#17583057 を参照)の時点で、生成された拡張ファイルに次の定義を追加することができます。
extension PersonModel {
// This is what got generated by core data
@NSManaged var name: String?
@NSManaged var hairColor: NSNumber?
@NSManaged var parents: NSSet?
// This is what I manually added
@NSManaged func addParentsObject(value:ParentModel)
@NSManaged func removeParentsObject(value:ParentModel)
@NSManaged func addParents(value:Set<ParentModel>)
@NSManaged func removeParents(value:Set<ParentModel>)
}
これが機能するのは
NSManaged属性は、Core Dataの自動生成されたKey-Value-Coding準拠の多対多アクセサにアクセスするために、メソッドとプロパティとともに使用できます。
この定義を追加すると、コレクションにアイテムを追加できます。これらがなぜ自動的に生成されないのかわからない...
Objective Cのコアデータは、セッターメソッドを自動的に作成します( 1 ):
デフォルトでは、Core Dataは、管理対象オブジェクトクラスのモデル化されたプロパティ(属性および関係)用の効率的なパブリックおよびプリミティブなgetおよびsetアクセサーメソッドを動的に作成します。これには、addable:やremoves:などのキーと値のコーディングが可能な可変プロキシメソッドが含まれます。これは、mutableSetValueForKey:のドキュメントで詳細が説明されています。
現在、Xcode6-Beta2ではSwiftになっているため、これらのアクセサーを自分で実装する必要があります。たとえば、Way
からNode
、次のようにaddNodesObject
を実装します。
class Way : NSManagedObject {
@NSManaged var nodes : NSSet
func addNodesObject(value: Node) {
self.mutableSetValueForKey("nodes").addObject(value)
}
}
ここで重要なのは、mutableSetValueForKey
/mutableOrderedSetValueForKey
/mutableArrayValueForKey
を使用する必要があるということです。これらのセット/配列では、addObjectを呼び出すことができ、次のフラッシュで保存されます。
NSMutableSetは、上記のソリューションを拡張してNSMutableSetであるため、Person NSManagedObjectを直接ロールに追加または削除できます。この場合、Personには1つのロールがあり、Rolesには多くのPersonがあります。
このソリューションをXcode Beta-3でテストしましたが、これは機能します!
このコードは部門を削除して、PersonからRolesにアクセスし、PersonsからRolesにアクセスするために必要な1対1および1対多のコードを簡単に表示できるようにします。
import CoreData
@objc(Person) class Person: NSManagedObject {
@NSManaged var name: String
//One to One relationship in your Model
@NSManaged var roles: Roles
}
@objc(Roles) class Roles: NSManagedObject {
@NSManaged var role: String
//One to Many relationship in your Model
@NSManaged var persons: NSMutableSet
}
extension Roles {
func addPersonsObject(value: Person) {
self.persons.addObject(value)
}
func removePersonsObject(value: Person) {
self.persons.removeObject(value)
}
func addPersons(values: [Person]) {
self.persons.addObjectsFromArray(values)
}
func removePersons(values: [Person]) {
for person in values as [Person] {
self.removePersonsObject(person)
}
}
}
代わりに、型指定されたSet
を使用するだけで、はるかに簡単になります。前の回答で@Nycenと@ lehn0058が提供した例に従って、次のように書くことができます。
extension PersonModel {
@NSManaged var parents: Set<ParentModel>?
}
そして、insert
のremove
およびSet
メソッドを使用します。
Xcode 8およびSwift 3.0の時点で、Xcodeは関係のアクセサーを生成するようになりました。たとえば、NSManagedObjectクラスStoreがあり、Itemsと1対多の関係があります。 SellsItems:ストア用に生成されたクラスには、SelsItemsに追加および削除するための以下の拡張子があります。
// MARK: Generated accessors for sellsItems
extension Store {
@objc(addSellsItemsObject:)
@NSManaged public func addToSellsItems(_ value: Item)
@objc(removeSellsItemsObject:)
@NSManaged public func removeFromSellsItems(_ value: Item)
@objc(addSellsItems:)
@NSManaged public func addToSellsItems(_ values: NSSet)
@objc(removeSellsItems:)
@NSManaged public func removeFromSellsItems(_ values: NSSet)
}
リレーションシップの片側のみを設定する必要があるので、最近では両方を設定する必要があるため、1 <->多くのリレーションシップがある場合は特に簡単です。 Departmentオブジェクトには複数のPersonオブジェクトがあり、次を使用できます。
aPerson.department = aDepartment
チェックすると、aDepartment.people(セットアップした相互関係であると仮定)に「aPerson」Personオブジェクトが含まれるようになります。
関係が多<->多の場合、上記のより複雑なソリューションの1つが必要になります。