2012-06-03 2 views
1

Хотят запросить фотографию в базе данных CoreDataкак вернуть результат после OpenWithCompletionHandler: завершения

это мой код

это категория NSObjectSubclass

//Photo+creak.h 

#import "Photo+creat.h" 

@implementation Photo (creat) 

+(Photo *)creatPhotoByString:(NSString *)photoName inManagedObjectContext:(NSManagedObjectContext *)context{ 
    Photo *picture = nil; 

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"]; 
    request.predicate = [NSPredicate predicateWithFormat:@"name = %@", photoName]; 

    NSArray *matches = [context executeFetchRequest:request error:nil]; 
    if (!matches || [matches count]>1) { 
     //error 
    } else if ([matches count] == 0) { 
     picture = [NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:context]; 
     picture.name = photoName; 
    } else { 
     picture = [matches lastObject]; 
    } 
    return picture; 
} 

+ (BOOL)isPhoto:(NSString *)photoName here:(NSManagedObjectContext *)context{ 
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"]; 
    request.predicate = [NSPredicate predicateWithFormat:@"name = %@", photoName]; 
    NSArray *matches = [context executeFetchRequest:request error:nil]; 
    switch ([matches count]) { 
     case 1: 
      return YES; 
      break; 
     default: 
      return NO; 
      break; 
    } 
} 
@end 

кода внутри вида контроллера

//View Controller 
- (IBAction)insertData:(UIButton *)sender { 
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    url = [url URLByAppendingPathComponent:@"test"]; 
    UIManagedDocument *defaultDocument = [[UIManagedDocument alloc] initWithFileURL:url]; 
    if (![[NSFileManager defaultManager] fileExistsAtPath:[url path]]) { 
     [defaultDocument saveToURL:defaultDocument.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:NULL]; 
    } 
    [defaultDocument openWithCompletionHandler:^(BOOL success) { 
     [Photo creatPhotoByString:@"test" inManagedObjectContext:defaultDocument.managedObjectContext]; 
     [defaultDocument saveToURL:defaultDocument.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL]; 
    }]; 
    [sender setTitle:@"Okay" forState:UIControlStateNormal]; 
    [sender setEnabled:NO]; 
} 

- (IBAction)queryFromDatabase:(UIButton *)sender { 
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    url = [url URLByAppendingPathComponent:@"test"]; 
    UIManagedDocument *defaultDocument = [[UIManagedDocument alloc] initWithFileURL:url]; 
    BOOL isItWorking = [checkPhoto isPhoto:@"test" inManagedDocument:defaultDocument]; 
    if (isItWorking) { 
     [sender setTitle:@"Okay" forState:UIControlStateNormal]; 
    } else { 
     [sender setTitle:@"NO" forState:UIControlStateNormal]; 
    } 
} 

Класс NSObject, который соединяет их.

// checkPhoto.m 
#import "checkPhoto.h" 
@implementation checkPhoto 
+ (BOOL)isPhoto:(NSString *)photoToCheck inManagedDocument:(UIManagedDocument *)document{ 
    __block BOOL isPhotoHere = NO; 
    if (document.documentState == UIDocumentStateClosed) { 
     [document openWithCompletionHandler:^(BOOL success) { 
      isPhotoHere = [Photo isPhoto:photoToCheck here:document.managedObjectContext]; 
     }]; 
    } 
    return isPhotoHere; 
} 
@end 

Корнедаты имеют только объект, названный «Фото», и он получил только один атрибут «имя». Проблема заключается в том, что возврат всегда выполняется до завершения блока и всегда возвращает NO. Код испытания here

Или мне нужно сделать что-то еще, чем openWithCompletionHandler при запросе?

ответ

2

Вам необходимо переработать свой метод для работы асинхронно, например -openWithCompletionHandler:. Он должен взять блок, который вызывается, когда ответ известен и который принимает ответ, true или false, в качестве параметра.

Затем вызывающий должен пройти в блоке, который делает все, что должно произойти после того, как ответ будет известен.

Или, альтернативно, вы должны отложить весь фрагмент логики, который заботится о том, что фотография находится в базе данных. Это должно быть сделано после завершения открытия.

Вам нужно будет показать больше кода для более конкретного предложения.


Таким образом, вы могли бы переработать метод isPhoto... к чему-то вроде:

+ (BOOL)checkIfPhoto:(NSString *)photoToCheck isInManagedDocument:(UIManagedDocument *)document handler:(void (^)(BOOL isHere))handler { 
    if (document.documentState == UIDocumentStateClosed) { 
     [document openWithCompletionHandler:^(BOOL success) { 
      handler([Photo isPhoto:photoToCheck here:document.managedObjectContext]); 
     }]; 
    } 
    else 
     handler(NO); 
} 

Тогда вы можете переделать это:

- (IBAction)queryFromDatabase:(UIButton *)sender { 
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    url = [url URLByAppendingPathComponent:@"test"]; 
    UIManagedDocument *defaultDocument = [[UIManagedDocument alloc] initWithFileURL:url]; 
    [checkPhoto checkIfPhoto:@"test" isInManagedDocument:defaultDocument handler:^(BOOL isHere){ 
     if (isHere) { 
      [sender setTitle:@"Okay" forState:UIControlStateNormal]; 
     } else { 
      [sender setTitle:@"NO" forState:UIControlStateNormal]; 
     } 
    }]; 
} 
+1

Я не собираюсь читать весь ваш проект. Покажите конкретный код, который касается фотографии, находящейся в базе данных. –

+0

вы правы ... :) Но я понятия не имею, как это исправить. вы можете взглянуть на этот [Тестовый код] (https://docs.google.com/open?id=0B519iRTC07VBUF84ZHVVSVFkcVk) –

+0

Мне очень жаль, я не собирался публиковать весь проект, я не тихий, знакомый с stackoverflow. Я редактировал сообщение и нажимал return, предполагая, что он запустит новую строку. извините, если это кажется грубым.) –

0

Попробуйте что

+(BOOL)isPhoto:(Photo *)photo inDataBase:(UIManagedDocument *)defaultDocument{ 
__block BOOL isPhotoThere = NO; 
dispatch_semaphore_t sema = dispatch_semaphore_create(0); 
[defaultDocument openWithCompletionHandler:^(BOOL success) { 
    [defaultDocument.managedObjectContext performBlock:^{ 
     isPhotoThere = [Photo checkPhoto:photo]; 
     dispatch_semaphore_signal(sema); 
    }]; 
}]; 
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
dispatch_release(sema); 
return isPhotoThere; 
} 
+0

Это * может * работать, или это может быть не так, если '-openWithCompletionHandler:' зависит от вызывающего потока, запускающего цикл выполнения. –

+0

печально нет, он застыл. Мне кажется, что есть и то и другое в той же теме, это действительно проводной. Можете ли вы взглянуть на него? [code] (https://docs.google.com/open?id=0B519iRTC07VBUF84ZHVVSVFkcVk) –

+0

@KyleFang, вероятно, использует NSRunLoop, поэтому для завершения этого блока требуется, чтобы текущий тик интерфейса завершился до того, как блок будет выполнен. –

Смежные вопросы