我正在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中是否有类似于动画完成块的内容?
答案 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;
});