1

我在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 需要一个 void 代码块。我怎样才能在 IOS 中实现相同的目标?IOS中是否有类似动画完成块的东西?

4

4 回答 4

2

该块必须具有 void 返回类型,因为在异步块中没有将值返回到的地方。

变量 isExisting 是合格的__block,这意味着只要块分配给它,它就会被设置。不幸的是,一旦退出范围,您的主线程将无法访问它。谨慎的做法是让您的块调用另一个方法(或函数或块)来设置您知道在异步块完成时仍然存在的变量或属性。

例如,您可以在应用程序委托上有一个方法,以便在完成时调用。

// 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 更新。

于 2013-10-24T12:33:59.397 回答
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,...(如果需要,请不要原谅 *)

于 2013-10-24T12:32:34.997 回答
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;
    });
于 2013-10-24T12:21:26.593 回答
0

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

于 2013-10-24T11:56:56.860 回答