2010-10-07 31 views
7

Tôi đang gặp sự cố khi tìm hiểu cách thể hiện mô hình mối quan hệ nhiều-nhiều trong một NSTokenField. Tôi có hai mô hình (có liên quan):NSTokenField đại diện cho dữ liệu cốt lõi cho nhiều mối quan hệ

mục Tag

Một mặt hàng có thể có nhiều thẻ và một thẻ có thể có nhiều mặt hàng. Vì vậy, nó là một mối quan hệ nghịch đảo nhiều.

Điều tôi muốn làm là đại diện cho các thẻ này trong NSTokenField. Tôi muốn kết thúc với một tokenfield tự động đề xuất các trận đấu (phát hiện ra một cách để làm điều đó với tokenfield: completionsForSubstring: indexOfToken: indexOfSelectedItem) và có thể thêm các thực thể thẻ mới nếu nó không phù hợp với hiện tại.

Được rồi, hy vọng bạn vẫn ở bên tôi. Tôi đang cố gắng làm tất cả điều này với các ràng buộc và bộ điều khiển mảng (vì điều đó có ý nghĩa nhất, phải không?)

Tôi có một bộ điều khiển mảng, "Item Array Controller", đó là ràng buộc với đại biểu ứng dụng managedObjectContext của tôi. Một tableview hiển thị tất cả các mục có một ràng buộc để điều khiển mảng này.

Giá trị NSTokenField của tôi có ràng buộc với khóa lựa chọn bộ điều khiển mảng và đường dẫn khóa mô hình: thẻ.

Với cấu hình này, NSTokenField sẽ không hiển thị các thẻ. Nó chỉ mang lại cho tôi:

<NSTokenFieldCell: 0x10014dc60>: Unknown object type assigned (Relationship objects for {(
    <NSManagedObject: 0x10059bdc0> (entity: Tag; id: 0x10016d6e0 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Tag/p102> ; data: <fault>) 
)} on 0x100169660). Ignoring... 

Điều này có ý nghĩa với tôi, vì vậy đừng lo lắng. Tôi đã xem xét một số phương pháp đại biểu NSTokenField và có vẻ như tôi nên sử dụng:

- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject 

Vấn đề là, phương pháp này không được gọi và tôi gặp lỗi tương tự như trước đây.

Được rồi, vì vậy động thái tiếp theo của tôi là thử và tạo một ValueTransformer. Chuyển đổi từ một mảng với thực thể thẻ -> mảng có chuỗi (tên thẻ) đều tốt. Cách khác là khó khăn hơn.

Những gì tôi đã cố gắng là tra cứu mọi tên trong ứng dụng được chia sẻ của tôi ủy quyền bối cảnh đối tượng được quản lý và trả về các thẻ phù hợp. Điều này mang lại cho tôi một vấn đề với các bối cảnh đối tượng được quản lý khác nhau rõ ràng:

Illegal attempt to establish a relationship 'tags' between objects in different contexts (source = <NSManagedObject: 0x100156900> (entity: Item; id: 0x1003b22b0 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Item/p106> ; data: { 
author = "0x1003b1b30 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Author/p103>"; 
createdAt = nil; 
filePath = nil; 
tags =  (
); 
title = "Great presentation"; 
type = "0x1003b1150 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Type/p104>"; 
}) , destination = <NSManagedObject: 0x114d08100> (entity: Tag; id: 0x100146b40 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Tag/p102> ; data: <fault>)) 

Tôi sẽ làm gì sai? Làm cách nào để giải quyết vấn đề này? Có phải đó là cách tiếp cận đúng (có vẻ lạ với tôi rằng bạn phải sử dụng một ValueTransformer?)

Cảm ơn bạn trước!

+0

Tôi đã dành nhiều thời gian nghiên cứu hơn cho hôm nay - vẫn không thể tìm thấy tài nguyên giải thích điều này. Tôi hy vọng ai đó sẽ đến giải cứu ở đây! :) – simonwh

Trả lời

7

Tôi đã viết một tùy chỉnh NSValueTransformer để ánh xạ giữa các ràng buộc NSManagedObject/TagNSSetNSStringNSArray của trường mã thông báo.Dưới đây là 2 phương pháp:

- (id)transformedValue:(id)value { 
    if ([value isKindOfClass:[NSSet class]]) { 
    NSSet *set = (NSSet *)value; 
    NSMutableArray *ary = [NSMutableArray arrayWithCapacity:[set count]]; 
    for (Tag *tag in [set allObjects]) { 
     [ary addObject:tag.name]; 
    } 
    return ary; 
    } 
    return nil; 
} 

- (id)reverseTransformedValue:(id)value { 
    if ([value isKindOfClass:[NSArray class]]) { 
    NSArray *ary = (NSArray *)value; 
    // Check each NSString in the array representing a Tag name if a corresponding 
    // tag managed object already exists 
    NSMutableSet *tagSet = [NSMutableSet setWithCapacity:[ary count]]; 
    for (NSString *tagName in ary) { 
     NSManagedObjectContext *context = [[NSApp delegate] managedObjectContext]; 
     NSFetchRequest *request = [[NSFetchRequest alloc] init]; 

     NSPredicate *searchFilter = [NSPredicate predicateWithFormat:@"name = %@", tagName]; 
     NSEntityDescription *entity = [NSEntityDescription entityForName:[Tag className] inManagedObjectContext:context]; 

     [request setEntity:entity]; 
     [request setPredicate:searchFilter]; 

     NSError *error = nil; 
     NSArray *results = [context executeFetchRequest:request error:&error]; 
     if ([results count] > 0) { 
     [tagSet addObjectsFromArray:results]; 
     } 
     else { 
     Tag *tag = [[Tag alloc] initWithEntity:entity insertIntoManagedObjectContext:context]; 
     tag.name = tagName; 

     [tagSet addObject:tag]; 
     [tag release]; 
     } 
    } 
    return tagSet; 
    } 
    return nil; 
} 

CoreData dường như để tự động thiết lập các mối quan hệ đối tượng trên lợi nhuận (nhưng tôi đã không hoàn toàn xác nhận này chưa)

Hy vọng nó giúp.

0

2 câu hỏi:

1) Bạn có NSManagedObjectContext đang được sử dụng khác với ngữ cảnh của đại biểu ứng dụng của bạn không? 2) Là đối tượng thực hiện tokenField: displayStringForRepresentedObject: thiết lập làm đại biểu cho NSTokenField?

1

Lỗi thứ hai của bạn là do có hai bối cảnh đối tượng được quản lý riêng biệt với cùng một kiểu và lưu trữ hoạt động cùng một lúc. Bạn đang cố tạo một đối tượng trong một ngữ cảnh và sau đó liên kết nó với một đối tượng khác trong ngữ cảnh thứ hai. Điều đó không được phép. Bạn cần phải mất bối cảnh thứ hai và làm cho tất cả các mối quan hệ của bạn trong một bối cảnh duy nhất.

Lỗi ban đầu của bạn là do đường phím không đầy đủ. Từ mô tả của bạn, có vẻ như bạn đang cố điền các trường mã thông báo với ItemsArrayController.selectedItem.tags nhưng điều đó sẽ chỉ trả lại đối tượng Tag mà mã thông báo được gửi không thể sử dụng. Thay vào đó, bạn cần cung cấp cho nó thứ gì đó chuyển đổi thành chuỗi, ví dụ: ItemsArrayController.selectedItem.tags.name

Các vấn đề liên quan