在iOS應用程序中,我試圖從具有100萬行的表中的SQLite字段中去除變音符號。iOS應用程序中的SQLite C函數導致EXC_BAD_ACCESS
編輯:該original answer I referenced has been updated其作者以反映下面的接受的答案。對於任何嘗試做同樣事情的人來說,這是最好的答案。
我從an earlier answer by Rob得到了一個很好的開始。爲了這個問題的目的,我試圖使用INSERT INTO ... SELECT ... FROM ...
聲明將表複製到另一個表。直到我介紹一個C函數從外地口音剝離和其他變音符號也能正常工作:
INSERT INTO DestinationTable (MasterField, SubField, IndexID) SELECT unaccented(MasterField), SubField, IndexID FROM SourceTable
隨着推出unaccented()
功能,我經常收到我將在下文指定EXC_BAD_ACCESS。但引人注目的是,SQLite操作有時會成功完成所有100萬行。當我擴展負載以複製500萬行時,應用程序將始終崩潰。
TL; DR
下面是我的源代碼,與EXC_BAD_ACCESS點評論在第一函數的底部:
#import <sqlite3.h>
sqlite3 *db;
void unaccented(sqlite3_context *context, int argc, sqlite3_value **argv)
{
if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_TEXT) {
sqlite3_result_null(context);
return;
}
@autoreleasepool {
NSMutableString *string = [NSMutableString stringWithUTF8String:(const char *)sqlite3_value_text(argv[0])];
CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO);
char *buf = sqlite3_malloc(sizeof(char) * [string length] + 1);
strcpy(buf, [string UTF8String]);
sqlite3_result_text(context, buf, -1, sqlite3_free);
} // This is where I usually get "EXC_BAD_ACCESS (code=1, address=...)"
}
@implementation MyClass
- (void)myMethod
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDir = [documentPaths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:[[NSBundle mainBundle] resourcePath]];
NSString *fileName;
while (fileName = [directoryEnumerator nextObject])
{
if ([fileName hasSuffix:@".sqlite"])
{
if (![fileManager fileExistsAtPath: [cachesDir stringByAppendingPathComponent:fileName]] == YES)
{
if (![fileManager copyItemAtPath:[[NSBundle mainBundle] pathForResource:fileName ofType:@""] toPath:[cachesDir stringByAppendingPathComponent:fileName] error:&error])
{
NSLog(@"Error description - %@ \n", [error localizedDescription]);
NSLog(@"Error reason - %@", [error localizedFailureReason]);
}
else
{
NSLog(@"HAI %@", fileName);
[self openDB:[cachesDir stringByAppendingPathComponent:fileName]];
NSString *sqlCommand = @"INSERT INTO DestinationTable (MasterField, SubField, IndexID) SELECT unaccented(MasterField), SubField, IndexID FROM SourceTable";
char *sqlError;
if (sqlite3_exec(db, [sqlCommand UTF8String], NULL, NULL, &sqlError) != SQLITE_OK)
{
NSLog(@"sqlite3_exec INSERT NOT SQLITE_OK with error: %d: %s", sqlite3_errcode(db), sqlite3_errmsg(db));
}
[self closeDB];
NSLog(@"KTHXBYE %@", fileName);
}
}
}
}
}
- (void) openDB: (NSString *)filePath
{
if (sqlite3_open([filePath UTF8String], &db) != SQLITE_OK)
{
sqlite3_close(db);
}
else
{
[self createUnaccentedFunction];
}
}
- (void) closeDB
{
sqlite3_close(db);
}
- (void)createUnaccentedFunction
{
if (sqlite3_create_function_v2(db, "unaccented", 1, SQLITE_ANY, NULL, &unaccented, NULL, NULL, NULL) != SQLITE_OK)
{
NSLog(@"%s: sqlite3_create_function_v2 error: %s", __FUNCTION__, sqlite3_errmsg(db));
}
}
什麼我做錯了任何意見?
我不知道這是保利的問題的根源,但是這是一個很好的修正,常規!我已經更新了我原來的帖子。 – Rob
哇,令人難以置信。它只是攪動了5000萬條記錄,沒有CPU或內存尖峯。謝謝! –