0

我在 Core Data 上遇到了麻烦,已经让我发疯了一天多。当我使用 Xcode 退出我的应用程序时,我失去了所有核心数据关系。所有对象仍在 SQL 数据库中,但它们之间的关系已经消失。我看了看这是最接近的东西:

关闭应用程序后,某些 CoreData 关系丢失

我尝试使用 mutableSetValueForKeyPath:

if ([[NSString stringWithFormat:@"%@",[item mutableSetValueForKeyPath:@"clothing_type"]] isEqualToString:@"Top"])
            return item;

但我只是得到:

'NSInvalidArgumentException',原因:'实体'ClothingItem' 的 NSManagedObjects 不支持 -mutableSetValueForKey:对于属性'clothing_type''

有人可以帮忙吗?下面的代码是主要问题发生的地方。我设置了衣柜,一切都很好。getTop、getBottom 和 getShoes 在视图等之间工作正常。即使应用程序进入后台并返回,一切都很好。但是我通过 xcode 退出了应用程序,当我回来时运行调试器并且衣柜就在那里,但是当我在上面运行 getTop、getBottom 或 getShoes 时,它返回 nil,因为 @dynamic 衣服是 nil。这是衣柜文件:

#import "Wardrobe.h"
#import "ClothingItem.h"


@implementation Wardrobe

@dynamic clothes;

- (ClothingItem*) getTop
{
        for (ClothingItem *item in clothes){

            if ([[item valueForKey:@"clothing_type"] isEqualToString:@"Top"])
                return item;
        }

    return nil;
}

- (ClothingItem*) getBottom
{
        for (ClothingItem *item in clothes){

            if ([[item valueForKey:@"clothing_type"] isEqualToString:@"Bottom"])
                return item;
        }

    return nil;
}

- (ClothingItem*) getShoes
{
        for (ClothingItem *item in clothes){

            if ([[item valueForKey:@"clothing_type"] isEqualToString:@"Shoes"])
                return item;
        }

    return nil;
}

@end

这是我设置收藏夹的地方。我最初将它保存为多维 NSMutableArray 并将其存储在 NSUserDefaults 中,但当我返回时它又消失了。我猜多维 NSMutableArray 不能以这种方式存储。所以我决定使用 Core Data,这似乎是最合适的做法:

- (IBAction)saveCurrentAsFavorite:(id)sender {
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

NSManagedObject *top = nil;
NSManagedObject *bottom = nil;
NSManagedObject *shoes = nil;

UIAlertView *myAlert;

if (delegate.topClothesList.count > delegate.currentTopNumber){
    top = [delegate.topClothesList objectAtIndex:delegate.currentTopNumber];
}
else {
    UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle: @"No Top!" message: @"Please select a top if you want to add to favorites!" delegate: nil cancelButtonTitle:@"Okie dokie!" otherButtonTitles:nil];
    [myAlert show];
    return;
}

if (delegate.bottomClothesList.count > delegate.currentBottomNumber){
    bottom = [delegate.bottomClothesList objectAtIndex:delegate.currentBottomNumber];
}
else {
    UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle: @"No Bottom!" message: @"Please select a bottom if you want to add to favorites!" delegate: nil cancelButtonTitle:@"Roger!" otherButtonTitles:nil];
    [myAlert show];
    return;
}

if (delegate.shoesClothesList.count > delegate.currentShoeNumber){
    shoes = [delegate.shoesClothesList objectAtIndex:delegate.currentShoeNumber];
}
else {
    //shoes = nil;
    UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle: @"No Shoes!" message: @"Please select shoes if you want to add to favorites!" delegate: nil cancelButtonTitle:@"Will do!" otherButtonTitles:nil];
    [myAlert show];
    return;
}

// The old way of doing it where I saved it all in an NSMutableArray, but it wouldn't save into NSUserDefaults as a multidimensional NSMutableArray…

/*            NSMutableArray *wardrobe = [[NSMutableArray alloc] initWithObjects:top, bottom, shoes, nil];

            for (int i = 0; i < delegate.favoriteWardrobes.count; i++){

                if ([[[delegate.favoriteWardrobes objectAtIndex:i] objectAtIndex:0] isEqual: [wardrobe objectAtIndex:0]] && [[[delegate.favoriteWardrobes objectAtIndex:i] objectAtIndex:1] isEqual: [wardrobe objectAtIndex:1]] && [[[delegate.favoriteWardrobes objectAtIndex:i] objectAtIndex:2] isEqual: [wardrobe objectAtIndex:2]]){
                    myAlert = [[UIAlertView alloc] initWithTitle: @"Wardrobe Already In Favorites!" message: @"Very nice choice, again! You like this wardrobe, so you should just buy it! Click the images so you could visit their sites and buy them!" delegate: nil cancelButtonTitle:@"Nice!" otherButtonTitles:nil];
                    [myAlert show];
                    return;
                }
            }

[delegate.favoriteWardrobes addObject:wardrobe];

// save information
NSArray *values = [[NSArray alloc] initWithObjects:delegate.selectedTopStyles, delegate.selectedBottomStyles, delegate.selectedShoesStyles, delegate.selectedSexes, delegate.selectedPrices, delegate.favoriteWardrobes, nil];
[values writeToFile:[self saveFilePath] atomically:YES];

//[[NSUserDefaults standardUserDefaults] setObject:delegate.favoriteWardrobes forKey:@"favoriteWardrobes"];

    myAlert = [[UIAlertView alloc] initWithTitle: @"Wardrobe Added To Favorites!" message: @"Very nice choice! Awesome style! \n\nReminder: if you select View Favorities you can send this wardrobe to yourself and your friends!" delegate: nil cancelButtonTitle:@"Sweet!" otherButtonTitles:nil];
    [myAlert show];

*/

// TRY DOING IT THE CORE DATA WAY

// need to fetch the Wardrobe objects and check their children to see if they match; and if any of these children do not exist within that wardrobe, skip it. If there is a wardrobe that contains all three then say wardrobe is already added

NSEntityDescription *entitydesc = [NSEntityDescription entityForName:@"Wardrobe" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];

[request setIncludesSubentities:NO];

NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:request error:&error];
ClothingItem *clothingTop, *clothingBottom, *clothingShoes;

for (Wardrobe *ward in fetchedObjects) {
    clothingTop = [ward getTop];
    clothingBottom = [ward getBottom];
    clothingShoes = [ward getShoes];

    if (([[clothingTop valueForKey:@"clothing_id"] isEqual:[top valueForKey:@"clothing_id"]]) && ([[clothingBottom valueForKey:@"clothing_id"] isEqual:[bottom valueForKey:@"clothing_id"]]) && ([[clothingShoes valueForKey:@"clothing_id"] isEqual:[shoes valueForKey:@"clothing_id"]])){
        myAlert = [[UIAlertView alloc] initWithTitle: @"Wardrobe Already In Favorites!" message: @"Very nice choice, again! You like this wardrobe, so you should just buy it! Click the images so you could visit their sites and buy them!" delegate: nil cancelButtonTitle:@"Nice!" otherButtonTitles:nil];
        [myAlert show];
        return;

    }
}

// if there's no case like that and this wardrobe is unique then do the following:

// Grab the Wardrobe entity
Wardrobe *newWardrobe = [NSEntityDescription insertNewObjectForEntityForName:@"Wardrobe" inManagedObjectContext:context];



/*ClothingItem* topCloth = (ClothingItem *) top;
ClothingItem* bottomCloth = (ClothingItem *) bottom;
ClothingItem* shoesCloth = (ClothingItem *) shoes;*/

// Instead of doing straight casting because that doesn't seem recommended, do more fetch requests to be extra careful

//  We're looking to grab ClothingItems
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ClothingItem"
                                          inManagedObjectContext:context];

[fetchRequest setEntity:entity];


NSPredicate *predicate = [NSPredicate predicateWithFormat:@"clothing_id == %@", [top valueForKey:@"clothing_id"]];
[fetchRequest setPredicate:predicate];

error = nil;
fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

ClothingItem* topCloth = [fetchedObjects objectAtIndex:0];

predicate = [NSPredicate predicateWithFormat:@"clothing_id == %@", [bottom valueForKey:@"clothing_id"]];
[fetchRequest setPredicate:predicate];

error = nil;
fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

ClothingItem* bottomCloth = [fetchedObjects objectAtIndex:0];

predicate = [NSPredicate predicateWithFormat:@"clothing_id == %@", [shoes valueForKey:@"clothing_id"]];
[fetchRequest setPredicate:predicate];

error = nil;
fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

ClothingItem* shoesCloth = [fetchedObjects objectAtIndex:0];

// adding wardrobe to the clothes
[topCloth addWardrobeObject:newWardrobe];
[bottomCloth addWardrobeObject:newWardrobe];
[shoesCloth addWardrobeObject:newWardrobe];

// adding clothes to wardrobe
// adding individually just to see if it works this way; the NSSet below was working fine
[newWardrobe addClothesObject:topCloth];
[newWardrobe addClothesObject:bottomCloth];
[newWardrobe addClothesObject:shoesCloth];

//[newWardrobe addClothes:[NSSet setWithObjects:topCloth, bottomCloth, shoesCloth, nil]];

if ([context save:&error]) {
    NSLog(@"The save was successful!");
} else {
    NSLog(@"The save wasn't successful: %@", [error localizedDescription]);
}

//[delegate saveContext]; // does this help?

//[newWardrobe addClothesObject:[delegate.topClothesList objectAtIndex:delegate.currentTopNumber]];
//[newWardrobe addClothesObject:[delegate.bottomClothesList objectAtIndex:delegate.currentBottomNumber]];
//[newWardrobe addClothesObject:[delegate.shoesClothesList objectAtIndex:delegate.currentShoeNumber]];

// not sure if this is going to work!
//[newWardrobe addClothesObject:(ClothingItem*) top];
//[newWardrobe addClothesObject:(ClothingItem*) bottom];
//[newWardrobe addClothesObject:(ClothingItem*) shoes];

delegate.numFavorites++; // add another favorite
[[NSUserDefaults standardUserDefaults] setInteger:delegate.numFavorites forKey:@"numFavorites"];

myAlert = [[UIAlertView alloc] initWithTitle: @"Wardrobe Added To Favorites!" message: @"Very nice choice! Awesome style! \n\nReminder: if you select View Favorities you can send this wardrobe to yourself and your friends!" delegate: nil cancelButtonTitle:@"Sweet!" otherButtonTitles:nil];
[myAlert show];

}

这是我调用 getTop、getBottom、getShoes 的代码:

// Construct a fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Wardrobe"
                                          inManagedObjectContext:context];

[request setIncludesSubentities:NO];

[request setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:request error:&error];
//ClothingItem *clothingTop, *clothingBottom, *clothingShoes;

NSManagedObject *top = [[fetchedObjects objectAtIndex:currentWardobe] getTop];//[[delegate.favoriteWardrobes objectAtIndex:currentWardobe] objectAtIndex:0];
NSManagedObject *bottom = [[fetchedObjects objectAtIndex:currentWardobe] getBottom];//[[delegate.favoriteWardrobes objectAtIndex:currentWardobe] objectAtIndex:1];
NSManagedObject *shoes = [[fetchedObjects objectAtIndex:currentWardobe] getShoes];//[[delegate.favoriteWardrobes objectAtIndex:currentWardobe] objectAtIndex:2];

关于这里可能出了什么问题的任何想法?

4

0 回答 0