IOS中完成块的后台任务

时间:2013-10-24 11:48:10

标签: ios objective-c objective-c-blocks

我正在IOS中进行一些数据库操作。基本上我想在后台线程中执行此操作。我尝试使用GCD。但问题是我希望在完成后从这个过程中获得一些值。在将项目插入数据库之前说我检查该项目是否已存在。请参阅下面的代码

__block Boolean isExisting = false;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                             (unsigned long)NULL), ^(void) {
        NSString *path = [SqliteManager initDatabase];
        if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
        {
            NSString *query = [NSString stringWithFormat:@"select count (campaignId) from POTC where Id='%@' and taskid='%@' and pocId='%@' and userId='%@'",[submission.campaignId  stringRepresentation],[submission.taskId stringRepresentation],[submission.pocId stringRepresentation],[[UUID UUIDWithString:submission.userId] stringRepresentation]];
            const char *sql = [query cStringUsingEncoding:NSASCIIStringEncoding];
            sqlite3_stmt *selectStatement;
            if (sqlite3_prepare_v2(database, sql, -1, &selectStatement, NULL) == SQLITE_OK)
            {
                while (sqlite3_step(selectStatement) == SQLITE_ROW)
                {
                    if (sqlite3_column_int(selectStatement, 0) >0)
                    {
                        isExisting = true;
                        break;
                    }
                }
                sqlite3_finalize(selectStatement);
            }
            sqlite3_close(database);
        }
        return isExisting;
    });

但上面的带有return语句的代码不能正常工作,因为dispatch-async需要一个无效代码块。我怎样才能在IOS中实现同样的目标?在IOS中是否有类似于动画完成块的内容?

4 个答案:

答案 0 :(得分:2)

也许您应该使用完成块创建一个函数。

我定义了这样的地雷:

typedef void (^myBlock)(type1 param1,
                        type2 param2);

-(void)myAsyncFunctionWithParam:(id)paramSend withCompletionBlock:(myBlock)returningBlock
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //here everything you want to do
        // especially defining 2 parameters to return (let them be p1 & p2)
        dispatch_async(dispatch_get_main_queue(), ^{
            returningBlock(p1,p2);
        });
    });
}

你可以像以下一样使用它:

[self myAsyncFunctionWithParam:ps 
           withCompletionBlock:^(type1 paramToUse1,
                                 type2 paramToUse2)
           {
               //You can use here paramToUse1 and paramToUse2
           }
];

您可以在块中使用您想要的任何类型:NSString,NSDate,...(如果需要,请不要原谅*)

答案 1 :(得分:2)

该块必须具有返回类型的void,因为无法将值返回到异步块中。

变量isExisting是限定的__block,这意味着只要块指定它就会设置它。不幸的是,一旦退出范围,您的主线程将无法访问它。警惕这样做是为了让你的块调用另一个方法(或函数或块)来设置你知道在异步块完成时仍然存在的变量或属性。

e.g。你可以让app delegate上的方法在完成时调用。

// in your appDelegate implementation

-(void) updateUIAfterDatabaseUpdate: (bool) isExisting
{
    if (isExisting)
    {
        // e.g. display an error
    }
    else
    {
        // successful update
    }
}

// The update code

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                             (unsigned long)NULL), ^(void) {
        bool isExisting = false;

        NSString *path = [SqliteManager initDatabase];
        if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
        {
            // Snipped for clarity
        }
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            [appDelegate updateUIAfterDatabaseUpdate: isExisting] ;
        });
    });

主队列上的调度确保在主线程中调用该方法,以便它可以进行UI更新。

答案 2 :(得分:0)

您不必返回某些内容,因为isExisting将变为true,如果在块执行完成后访问其值,则返回true。

答案 3 :(得分:0)

你的思维方式失去了后台线程的好处:)。您应该重新构建程序以更好地适应异步范例。您以异步方式启动后台工作,然后在完成后,您可以向接收方发送消息以执行其他工作。例如,在您的代码中,您可以使用通知或简单的消息发送。像这样:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                             (unsigned long)NULL), ^(void) {
        NSString *path = [SqliteManager initDatabase];
        if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
        {
            NSString *query = [NSString stringWithFormat:@"select count (campaignId) from POTC where Id='%@' and taskid='%@' and pocId='%@' and userId='%@'",[submission.campaignId  stringRepresentation],[submission.taskId stringRepresentation],[submission.pocId stringRepresentation],[[UUID UUIDWithString:submission.userId] stringRepresentation]];
            const char *sql = [query cStringUsingEncoding:NSASCIIStringEncoding];
            sqlite3_stmt *selectStatement;
            if (sqlite3_prepare_v2(database, sql, -1, &selectStatement, NULL) == SQLITE_OK)
            {
                while (sqlite3_step(selectStatement) == SQLITE_ROW)
                {
                    if (sqlite3_column_int(selectStatement, 0) >0)
                    {

                      // Here you can send the notification with the data you want.
                        break;
                    }
                }
                sqlite3_finalize(selectStatement);
            }
            sqlite3_close(database);
        }
        return isExisting;
    });