web-dev-qa-db-ja.com

NSManagedObject関係をSwiftで設定する

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オブジェクトに戻す必要がありますか?

34
Andrew Ebling

ええ、それはもう動作しません、Swiftはこの方法で実行時にアクセサを生成できません、それは型システムを壊すでしょう。

あなたがしなければならないことは、キーパスを使用することです:

var manyRelation = myObject.valueForKeyPath("subObjects") as NSMutableSet
manyRelation.addObject(subObject)
/* (Not tested) */
32
iluvcapra

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準拠の多対多アクセサにアクセスするために、メソッドとプロパティとともに使用できます。

この定義を追加すると、コレクションにアイテムを追加できます。これらがなぜ自動的に生成されないのかわからない...

46
lehn0058

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を呼び出すことができ、次のフラッシュで保存されます。

19
Bouke

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)
        }
    }

}
6
BadDogApps

代わりに、型指定されたSetを使用するだけで、はるかに簡単になります。前の回答で@Nycenと@ lehn0058が提供した例に従って、次のように書くことができます。

extension PersonModel {
    @NSManaged var parents: Set<ParentModel>?
}

そして、insertremoveおよびSetメソッドを使用します。

6
FranMowinckel

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)
}
5
Mario Hendricks

リレーションシップの片側のみを設定する必要があるので、最近では両方を設定する必要があるため、1 <->多くのリレーションシップがある場合は特に簡単です。 Departmentオブジェクトには複数のPersonオブジェクトがあり、次を使用できます。

aPerson.department = aDepartment

チェックすると、aDepartment.people(セットアップした相互関係であると仮定)に「aPerson」Personオブジェクトが含まれるようになります。

関係が多<->多の場合、上記のより複雑なソリューションの1つが必要になります。

3
Peter