2016-11-21 192 views
1

我只是碰到了這個問題,即奇怪的結果上iOS10

+ (NSArray *)fetchMyStuffInContext:(NSManagedObjectContext *)_moc 
{ 
    NSFetchRequest *request; 
    NSPredicate  *pred; 
    __block NSError *error; 
    __block NSArray *myStuff; 

    request = [[NSFetchRequest alloc] initWithEntityName:@"myobs"]; 
    pred = [NSPredicate predicateWithFormat:@"anAttribute == YES"]; 
    [request setPredicate:pred]; 

    error = nil; 
    [_moc performBlockAndWait:^{ 
    myStuff = [_moc executeFetchRequest:request error:&error]; 
    }]; 
    [request release]; 

    if (error) { 
    NSLog(@"Error while fetching:\n%@", 
     ([error localizedDescription] != nil) ? 
     [error localizedDescription] : @"Unknown Error"); 
    return [NSArray array]; 
    } 

    return myStuff; 
} 

返回上iOS10 ID數組和iOS9管理對象的數組。

iOS9導致po myStuff

<_PFArray 0x16589ee0>(
    <MyObj: 0x16589bb0> (
    entity: myobs; 
    id: 0xd000000000040000 <x-coredata://81E85B5C-6504-4269-974B-5AB4449658DC/myobs/p1> ; 
    data: <fault>)) 

iOS10導致po myStuff

<__NSArrayM 0x170053e90>(
    0xd000000000040000 <x-coredata://81E85B5C-6504-4269-974B-5AB4449658DC/myobs/p1> 
) 

這是爲什麼?

在iOS上10,我可以通過調用

[moc objectWithID:] 

缺少什麼我在這裏檢索對象?

+1

主要是你錯過了,設置了這種讀取請求時,它真正需要的代碼包括在你的問題中。 –

+0

@TomHarrington感謝您的評論。我更新了代碼。 – lupz

回答

0

好的,我明白了!導致這種情況的核心數據行爲發生了變化。它甚至被記錄在Apple's What's new In CoreData

performBlockAndWait: implicitly includes an autorelease pool around each block. Projects using ARC or Swift should be generally unaffected, although remember that both NSError** out parameters and exceptions are autoreleased and do not escape block lexical scope happily. Projects using manual retain/release will need to retain autoreleased objects, including the results of executeFetchRequest:error: inside the block and release or autorelease them outside the block's lexical scope.

Jaix ....

因此,解決辦法是通過performBlockAndWait獲取這樣的時候保留和釋放的結果陣列:

/* ... */ 
__block NSArray *result; 

/* ... */ 

[moc performBlockAndWait:^{ 
    result = [[moc executeFetchRequest:request error:&error] retain]; 
}]; 

/* ... */ 

return [result autorelease]; 

奇怪儘管如此,文檔聲明

Core Data has changed two behaviors for applications built with a minimum deployment target of [..] iOS 10.0 [..].

我的IPHONEOS_DEPLOYMENT_TARGET仍然設置爲6.0所以我會認爲不是這樣。

但是,我試圖構建一箇舊的iPhoneOS9.2.sdk,我從Xcode7鏈接。 只要將舊SDK連接到Xcode文件夾(並更新Info.plist中的MinimumSDKVersion),即使當我將BaseSDK項目設置保留爲10.1時,也會讓錯誤消失。


我隔離在一個視圖控制器的問題(有一個按鈕;))這樣的:

#import <CoreData/CoreData.h> 
#import "ViewController.h" 

//------------------------------- Data entries. -------------------------------- 

@interface MyObj : NSManagedObject {} 
    @property (nonatomic, retain) NSNumber *attribute; 
@end 
@implementation MyObj 
    @dynamic attribute; 
@end 

//----------------------------- View controller. ------------------------------- 

@interface ViewController() { 
    NSOperationQueue    *m_q; 
    NSURL      *m_dataURL; 
    NSManagedObjectModel   *m_model; 
    NSPersistentStoreCoordinator *m_store; 
} 
@end 

@implementation ViewController 

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 
    m_q  = [[NSOperationQueue alloc] init]; 
    m_dataURL = [[[[[NSFileManager defaultManager] 
        URLsForDirectory:NSDocumentDirectory 
        inDomains:NSUserDomainMask] 
       lastObject] 
       URLByAppendingPathComponent:@"mydata"] 
       retain]; 
    m_model = [[self _createModel] retain]; 
    m_store = [[self _createStore:m_model] retain]; 
} 

- (void) dealloc 
{ 
    [m_q release]; 
    [m_dataURL release]; 
    [m_model release]; 
    [m_store release]; 

    [super dealloc]; 
} 

- (void) refreshUI 
{ 
    if (![NSThread isMainThread]) { 
    [self performSelectorOnMainThread:@selector(refreshUI) 
          withObject:nil 
         waitUntilDone:NO]; 
    return; 
    } 
    [self _loadData]; 
} 

- (IBAction) buttonClicked:(id)sender 
{ 
    NSBlockOperation  *create; 
    NSInvocationOperation *refresh; 

    create = [[NSBlockOperation alloc] init]; 
    [create addExecutionBlock:^{ 
    [self _createAndSaveData]; 
    }]; 

    refresh = [[NSInvocationOperation alloc] 
      initWithTarget:self 
      selector:@selector(refreshUI) 
      object:nil]; 
    [refresh addDependency:create]; 

    [m_q addOperation:create]; 
    [m_q addOperation:refresh]; 

    [create release]; 
    [refresh release]; 
} 

//--------------------------- Simple model. ------------------------------------ 

- (NSManagedObjectModel *)_createModel 
{ 
    NSManagedObjectModel *model; 
    NSEntityDescription *entity; 
    NSMutableArray   *properties; 
    NSAttributeDescription *attribute; 

    properties = [[NSMutableArray alloc] init]; 
    entity = [[NSEntityDescription alloc] init]; 
    [entity setName:@"myobj"]; 
    [entity setManagedObjectClassName:@"MyObj"]; 

    attribute = [[NSAttributeDescription alloc] init]; 
    [attribute setName:@"attribute"]; 
    [attribute setAttributeType:NSInteger32AttributeType]; 
    [properties addObject:attribute]; 
    [attribute release]; 

    [entity setProperties:properties]; 
    [properties release]; 

    model = [[NSManagedObjectModel alloc] init]; 
    [model setEntities:@[entity]]; 

    [entity release]; 

    return [model autorelease]; 
} 

- (NSPersistentStoreCoordinator *)_createStore:(NSManagedObjectModel *)model 
{ 
    NSPersistentStoreCoordinator *coordinator; 
    NSError      *error; 
    NSPersistentStore   *store; 

    error  = nil; 
    coordinator = [[NSPersistentStoreCoordinator alloc] 
       initWithManagedObjectModel:model]; 
    store  = [coordinator addPersistentStoreWithType:NSSQLiteStoreType 
              configuration:nil 
                URL:m_dataURL 
               options:nil 
                error:&error]; 
    if (!store) { 
    [coordinator release]; 
    abort(); 
    } 

    return [coordinator autorelease]; 
} 

- (NSManagedObjectContext *)createContext: 
    (NSManagedObjectContextConcurrencyType)type 
{ 
    NSManagedObjectContext *ctx; 

    ctx = [[NSManagedObjectContext alloc] initWithConcurrencyType:type]; 
    [ctx performBlockAndWait:^{ 
    [ctx setPersistentStoreCoordinator:m_store]; 
    }]; 

    return [ctx autorelease]; 
} 

//----------------------------- Data actions. ---------------------------------- 

- (void) _createAndSaveData 
{ 
    NSManagedObjectContext *moc; 

    moc = [self createContext:NSPrivateQueueConcurrencyType]; 
    [moc performBlockAndWait:^{ 
    MyObj *obj; 
    obj = [[MyObj alloc] 
      initWithEntity:[[m_model entitiesByName] objectForKey:@"myobj"] 
      insertIntoManagedObjectContext:moc]; 
    [obj setAttribute: 
    [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]]; 
    [moc save:nil]; 
    [obj release]; 
    }]; 
} 

- (NSArray *)_loadData 
{ 
    NSManagedObjectContext *moc; 
    NSFetchRequest   *request; 
    __block NSError  *error; 
    __block NSArray  *objs; 

    moc  = [self createContext:NSMainQueueConcurrencyType]; 
    request = [[NSFetchRequest alloc] initWithEntityName:@"myobj"]; 
    error = nil; 
    [moc performBlockAndWait:^{ 
    // Retain here because of new autorelease pool! 
    objs = [[moc executeFetchRequest:request error:&error] retain]; 
    }]; 
    [request release]; 

    if (error) { 
    return [NSArray array]; 
    } 

    return [objs autorelease]; 
} 

@end