2017-04-17 28 views
0

該應用程序將數據保存在很多不同的類別中,每個類別都有自己的數據庫。 當你在類別之間切換時,你關閉/打開一個新的數據庫。iOS 10.3無法打開sqlite db

問題: 這些數據庫中的一些無法通過sqlite打開,其他數據庫使用完全相同的代碼按預期工作。

此外,最新更新(iOS 10.3)後,此問題開始。

獲取文件路徑:

-(NSString *) filePath { 
    NSString *appGroupId = @"xxx.xxx.extension"; 
    NSURL *appGroupDirectoryPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId]; 
    NSURL *dataBaseURL = [appGroupDirectoryPath URLByAppendingPathComponent:_detailItem]; 
    NSString *paths = dataBaseURL.path; 
return paths; 
} 

打開DB:

-(void)openDB { 
    if (sqlite3_open([[self filePath] UTF8String], &db) != SQLITE_OK) { 
     sqlite3_close(db); 
     NSLog(@"error"); 
    } 
    else{ 
     NSLog(@"Opened"); 
    } 
} 

所有DB的都使用此代碼打開,唯一的區別是文件名。 大多數文件名都包含特殊字符,如åäö。

Filenames/DB Names: 
ma värd 
ga väg A4 

-這些文件存在於同一個文件夾中。

兩個文件都包含數據,有些列甚至完全相同。

導向軸用相同的代碼創建

當試圖訪問第一個我得到一個空數據庫文件,所有SELECT語句返回「沒有這樣的表:表格名」

當試圖訪問第二一,一切都按預期工作。

之一,是許多SELECT語句:

-(NSString *)antalAsString:(NSString *)typAvAntal { 

    NSString *antalMatt = [[NSString alloc] init]; 
    NSString *sql = [NSString stringWithFormat:@"SELECT sum(antal) FROM '%@'", typAvAntal]; 
    sqlite3_stmt *statement; 
    NSLog(@"sql string: %@", sql); 

    const char *err; 
    if(sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, &err)==SQLITE_OK) 
    { 
     while (sqlite3_step(statement)==SQLITE_ROW) { 
      char *antal = (char *) sqlite3_column_text(statement, 0); 
      if (antal != NULL) { 
       antalMatt = [[NSString alloc]initWithUTF8String:antal]; 

       //.... 


       } 
      } 

     } 

    else { 
     NSLog(@"error: %s", sqlite3_errmsg(db)); 
    } 

    sqlite3_finalize(statement); 

    return antalMatt; 
} 

這怎麼可能?在iOS 10.3中,sqlite有什麼改變?

編輯/ UPDATE:

在文件夾中的每個文件都懷着的NSArray/NSLog的,看到含有特殊字符的文件名每次都被複製成另一種格式。

這2個文件:

Filenames/DB Names: 
ma värd 
ga väg A4 

都成了這4個文件:

ma va\U0308rd 
ma v\U00e4rd 

ga va\U0308g A4 
ga v\U00e4g A4 

當我嘗試檢查的文件大小 「馬VA \ U0308rd」,將字符串轉換成「馬värd「,所以我不知道哪兩個被引用。

NSString *sourcePath = [self filePath]; 

NSFileManager *fm = [NSFileManager defaultManager]; 
NSError *Error = nil; 
NSArray *sourceFiles = [fm contentsOfDirectoryAtPath:sourcePath error:&Error]; 
int i = 0; 
for (NSString *currentFile in sourceFiles) 
{ 
    if ([fm fileExistsAtPath:[sourcePath stringByAppendingPathComponent:[sourceFiles objectAtIndex:i]]]) 
    { 
     if ([currentFile hasPrefix:@"ma"]) 
     { 

     unsigned long long fileSize = [[fm attributesOfItemAtPath:[sourcePath stringByAppendingPathComponent:[sourceFiles objectAtIndex:i]] error:nil] fileSize]; 

      NSLog(@"FILE: %@ _______ SIZE: %llu", [sourceFiles objectAtIndex:i], fileSize); 
     } 
    } 
    else { 
     NSLog(@"NO FILE EXISTS: %@", currentFile); 

    } 
    i = i+1; 
} 

了很多問題:

爲什麼更新創建副本?

哪一個文件管理器選擇?

Sqlite會選擇哪一個?

有沒有辦法將「ma va \ U0308rd」聲明爲NSString而沒有將其轉換爲「mavärd」?

幫助表示讚賞。

+0

最有可能是因爲[有源電力濾波器(https://9to5mac.com/2017/03/21/what-is-apples-upcoming-apfs-apple-file-system-and-what-it -means-to-you /)在iOS 10.3中引入 – phi

+0

是的,您可能是對的,這些文件似乎完全無法到達,無法備份。將不得不刪除所有數據丟失的整個文件夾 – Niklas

回答

0

我不知道爲什麼更新會創建應用程序組文件夾中每個文件的重複項。 但瞭解到有一種方法可以控制使用特殊字符的unicode表單。看起來,如果沒有指定,系統會隨機挑選一個,或者選擇找到的第一個文件,而不管哪個表單有。

蘋果文檔:

> decomposedStringWithCanonicalMapping A string made by normalizing the 
> string’s contents using the Unicode Normalization Form D. 
> 
> decomposedStringWithCompatibilityMapping A string made by normalizing 
> the receiver’s contents using the Unicode Normalization Form KD. 
> 
> precomposedStringWithCanonicalMapping A string made by normalizing the 
> string’s contents using the Unicode Normalization Form C. 
> 
> precomposedStringWithCompatibilityMapping A string made by normalizing 
> the receiver’s contents using the Unicode Normalization Form KC. 

分解 - 使用的字符序列(A + \ U0308 = A)

預組成 - 使用唯一碼的每個字符(\ U00e4 = A)

能夠通過在所有數據之間進行切換來保存所有數據,以便訪問真實的數據庫文件並刪除已創建的「傻瓜」。

-(NSString *) filePath { 
     NSString *appGroupId = @"xxx.xxx.extension"; 
     NSURL *appGroupDirectoryPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId]; 
     NSURL *dataBaseURL = [appGroupDirectoryPath URLByAppendingPathComponent:_detailItem]; 
     NSString *paths = dataBaseURL.path.decomposedStringWithCompatibilityMapping; 

    return paths; 
    }