Надеюсь, вы извините за кажущуюся широкой природу этого вопроса, но он становится довольно конкретным.
Я создаю основанное на документе приложение Cocoa, которое работает, как и большинство других, за исключением того, что я использую SQLCipherдля моего хранилища данных (вариант SQLite), потому что вы не можете установить свое собственное постоянное хранилище данных в Core Data, а также мне действительно нужно использовать это.
В моем подклассе документа у меня есть свойство NSMutableArray
с именем categories
.В nib документа у меня есть NSArrayController
, связанный с categories
, и у меня есть NSCollectionView
, связанный с контроллером массива.
Каждый из моих объектов модели в массиве (каждыйCategory
) привязан к записи в базовом хранилище данных, поэтому, когда изменяется какое-либо свойство категории, я хочу вызвать [category save]
, когда категория добавляется в набор, я хочу снова вызвать [category save]
и, наконец, когда категория удаляется, [category destroy]
.
Я запрограммировал частичное решение, но оно не соответствует требованию удаления, и все в нем мне кажется, что яЛаю не то дерево.В любом случае, вот что происходит:
Как только документ и перо загружены, я начинаю наблюдать за свойством категорий и присваиваю ему некоторые данные:
[self addObserver:self
forKeyPath:@"categories"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
context:MyCategoriesContext];
self.categories = [Category getCategories];
Я реализовалметод наблюдения таким образом, что мне сообщают об изменениях, чтобы документ мог отвечать и обновлять хранилище данных.
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSNumber *changeKind = (NSNumber *)[change objectForKey:@"NSKeyValueChangeKind"];
if (context == MyCategoriesContext)
{
switch ([changeKind intValue])
{
case NSKeyValueChangeInsertion:
{
Category *c = (Category *)[change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"saving new category: %@", c);
[c save];
break;
}
case NSKeyValueChangeRemoval:
{
Category *c = (Category *)[change objectForKey:NSKeyValueChangeOldKey];
NSLog(@"deleting removed category: %@", c);
[c destroy];
break;
}
case NSKeyValueChangeReplacement:
{
// not a scenario we're interested in right now...
NSLog(@"category replaced with: %@", (Category *)[change objectForKey:NSKeyValueChangeNewKey]);
break;
}
default: // gets hit when categories is set directly to a new array
{
NSLog(@"categories changed, observing each");
NSMutableArray *categories = (NSMutableArray *)[object valueForKey:keyPath];
NSIndexSet *allIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [categories count])];
[self observeCategoriesAtIndexes:allIndexes];
break;
}
}
}
else if (context == MyCategoryContext)
{
NSLog(@"saving category for change to %@", keyPath);
[(Category *)object save];
}
else
{
// pass it on to NSObject/super since we're not interested
NSLog(@"ignoring change to %@:@%@", object, keyPath);
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
Как вы можете видеть из этого списка (и, как вы, возможно, уже знаете), недостаточно наблюдать за свойством categories
, мне нужно наблюдать за каждой отдельной категорией, чтобы документ уведомлялся, когда его атрибуты были изменены (например, имя), чтобы я мог сохранить это изменение немедленно:
- (void)observeCategoriesAtIndexes:(NSIndexSet *)indexes {
[categories addObserver:self
toObjectsAtIndexes:indexes
forKeyPath:@"dirty"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
context:MyCategoryContext];
}
Это выглядит для меня как большой удар, и я подозреваю, что я здесь работаю против Какао, но по большей части это работает.
За исключением удаления.Когда вы добавляете кнопку в свой интерфейс и назначаете ее для действия remove:
контроллера массива, она должным образом удалит категорию из свойства categories
в моем документе.
При этом категория освобождается, пока она еще находится под наблюдением:
2010-09-03 13:51:14.289 MyApp[7207:a0f] An instance 0x52db80 of class Category was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x52e100> (
<NSKeyValueObservance 0x2f1a480: Observer: 0x2f0fa00, Key path: dirty, Options: <New: YES, Old: YES, Prior: NO> Context: 0x1a67b4, Property: 0x2f1a3d0>
...
)
Кроме того, поскольку объект был освобожден до того, как меня уведомили, я неу меня есть возможность позвонить [category destroy]
от моего наблюдателя.
Как правильно интегрироваться с NSArrayController, чтобы сохранить изменения в модели данных до Core Data?Как можно обойти проблему удаления (или это неправильный подход?)
Заранее благодарен за любой совет!