【问题标题】:how to return result after OpenWithCompletionHandler: is completeOpen WithCompletionHandler: 完成后如何返回结果
【发布时间】:2012-06-03 07:50:22
【问题描述】:

想查询Coredata数据库中的一张照片

这是我的代码

这是 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 以外的其他操作吗?

【问题讨论】:

    标签: objective-c ios xcode core-data block


    【解决方案1】:

    您需要重新设计您的方法以异步工作,例如-openWithCompletionHandler:。它需要采用一个块,该块在已知答案时被调用,并接收答案,真或假,作为参数。

    然后,调用者应该传入一个块,该块执行已知答案后应该发生的任何事情。

    或者,或者,您应该延迟整个逻辑块,它关心照片是否在数据库中。应该在打开完成后完成。

    您必须为更具体的建议显示更多代码。


    因此,您可以将 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];
            }
        }];
    }
    

    【讨论】:

    • 我不会通读你的整个项目。显示关心数据库中照片的特定代码。
    • 你是对的...:) 但是,我不知道如何解决它。你能看看这个Test Code
    • 很抱歉,我并不是要发布整个项目,我对 stackoverflow 并不熟悉。我正在编辑帖子并点击返回,假设它将开始一个新行。对不起,如果这看起来很粗鲁。;)
    • 没关系。也许您最好的选择是编辑您的问题并在那里添加额外的代码,类似于您在原始问题中添加代码的方式。
    • 非常感谢,现在怎么样?这几乎是test code 中的所有内容。 (因为我不知道问题应该出在哪里,所以我不知道要发布哪个代码。我唯一能做的就是创建一个新项目并重新编写它。它只有3组文件。cmd+ s可以保存zip文件。我知道问的太多了,但你能帮我修一下吗)
    【解决方案2】:

    试试看

    +(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;
    }
    

    【讨论】:

    • 如果-openWithCompletionHandler: 依赖于运行其运行循环的调用线程,则此可能有效,也可能无效。
    • 很遗憾,它冻结了。我似乎两者都在同一个线程中,它真的是有线的。你能看看吗? code
    • @KyleFang 它可能使用了 NSRunLoop,所以它需要在执行块之前完成 UI 的当前滴答声。
    猜你喜欢
    • 2012-08-19
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-09
    • 2018-06-21
    • 2022-12-21
    • 2020-11-15
    相关资源
    最近更新 更多