2012-04-25 4 views
11

У меня есть приложение с предварительно заполненным файлом .sqlite, который копируется в каталог документов пользователя при первом открытии приложения. Этот файл составляет 12,9 МБ. Дважды в настоящее время, мое приложение было отклонено, так как изменения цель iOS5 с этим отбраковки примечание:Предварительная база данных iCloud и Core Data

Binary Отклонено 24 апреля, 2012 10:12 утра

причины для отказа:

2,23 приложения должны следовать Руководства по хранению данных iOS или они будут отклонены

24 апреля 2012 г. 10:12. От Apple.

2,23

Мы обнаружили, что ваше приложение не следовать Руководству IOS Data Storage, которая требуется согласно Руководству по App Store Review.

В частности, мы обнаружили, что при загрузке контента ваше приложение хранит 12,81 МБ. Чтобы проверить, сколько данных приложение хранит:

  • Установить и запустить приложение
  • Перейти в раздел Настройки> ICloud> Хранение & резервного копирования> Управление хранения
  • При необходимости, нажмите «Показать все приложения»
  • Проверьте хранение вашего приложения

Руководство для хранения данных IOS показывают, что только содержание, которое пользователь создает с помощью приложения, например, документы, новые файлы, редактирование и т.д., могут храниться в/Docum ents - и подкрепляется iCloud.

Временные файлы, используемые вашим приложением, должны храниться только в каталоге/tmp; не забудьте удалить файлы, хранящиеся в этом месте, когда пользователь выходит из приложения.

Данные, которые могут быть воссозданы, но должны сохраняться для правильной работы вашего приложения, или потому, что клиенты ожидают его доступности для использования в автономном режиме, должны быть отмечены атрибутом «не создавать резервные копии». Для объектов NSURL добавьте атрибут NSURLIsExcludedFromBackupKey, чтобы предотвратить резервное копирование соответствующего файла. Для объектов CFURLRef используйте соответствующий атрибут kCFURLIsExcludedFromBackupKey.

Для получения дополнительной информации см. Технические вопросы Q & A 1719: Как предотвратить резервное копирование файлов в iCloud и iTunes ?.

Необходимо изменить ваше приложение в соответствии с требованиями Руководства по хранению данных iOS.

Я попытался установить атрибут «не создавать резервные копии», как рекомендовано в Руководстве по хранению данных, но снова был отклонен.

Я не использую iCloud в своем приложении, а Settings> iCloud> и т. Д. Вообще не использует.

Я не могу использовать каталоги Caches или tmp, поскольку база данных изменена пользователем после создания.

Я, кажется, находится между камнем и твердым местом здесь, где Apple не позволяет этому виду приложений вообще функционировать.

У кого-нибудь была эта проблема и удалось ее преодолеть?

EDIT 17-5-12 Мне все еще не удалось получить это приложение еще. Кто-нибудь смог это сделать?

EDIT 1-7-12 Мое приложение только что было отклонено снова по той же причине. Я не понимаю, что здесь делать, так как это сценарий общего использования.

EDIT 11-9-12 Приложение одобрено - см. Мое решение ниже. Надеюсь, это поможет кому-то другому.

+0

Я столкнулся с этой проблемой. Меня беспокоит, что вас снова отвергли. Вы пытались установить атрибут во всей папке? Я беспокоюсь, что Apple просто отвергает модели данных, которые не являются основными данными. Если у вас есть какая-либо дополнительная информация, напишите ваши выводы. –

+0

Я был отклонен 3 раза за это. Я не пробовал устанавливать атрибут для всей папки документов, так как это не должно меняться. Было ли отклонено ваше приложение по этой причине? – colincameron

+0

Да. Вы решили сохранить файл БД в библиотеку? Возможно, это просто потому, что оно находится в папке/Documents, и это ТОЛЬКО для контента, созданного пользователем. Должна быть возможность написать свою собственную/базу данных. –

ответ

9

ОК, вот решение мне удалось получить одобрение

Это код для настройки резервного копирования атрибут Пропустить (наконец-то!) - обратите внимание, что она отличается для 5.0.1 и ниже и 5.1 и выше.

#include <sys/xattr.h> 
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL 
{ 
    if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1 
     const char* filePath = [[URL path] fileSystemRepresentation]; 

     const char* attrName = "com.apple.MobileBackup"; 
     u_int8_t attrValue = 1; 

     int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0); 
     return result == 0; 
    } else { // iOS >= 5.1 
     NSError *error = nil; 
     [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error]; 
     return error == nil; 
    } 
} 

А вот мой persistentStoreCoordinator

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 
    if (__persistentStoreCoordinator != nil) 
    { 
     return __persistentStoreCoordinator; 
    } 

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"store.sqlite"]; 

    NSError *error; 

    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSString *storePath = [[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent:@"store.sqlite"]; 

    // For iOS 5.0 - store in Caches and just put up with purging 
    // Users should be on at least 5.0.1 anyway 
    if ([[[UIDevice currentDevice] systemVersion] isEqualToString:@"5.0"]) { 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); 
     NSString *cacheDirectory = [paths objectAtIndex:0]; 
     NSString *oldStorePath = [storePath copy]; 
     storePath = [cacheDirectory stringByAppendingPathComponent:@"store.sqlite"]; 
     storeURL = [NSURL URLWithString:storePath]; 

     // Copy existing file 
     if ([fileManager fileExistsAtPath:oldStorePath]) { 
      [fileManager copyItemAtPath:oldStorePath toPath:storePath error:NULL]; 
      [fileManager removeItemAtPath:oldStorePath error:NULL]; 
     } 
    } 
    // END iOS 5.0 

    if (![fileManager fileExistsAtPath:storePath]) { 
     // File doesn't exist - copy it over 
     NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"store" ofType:@"sqlite"]; 
     if (defaultStorePath) { 
      [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL]; 
     } 
    } 

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) 
    { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 

    [self addSkipBackupAttributeToItemAtURL:storeURL]; 

    return __persistentStoreCoordinator; 
} 

Обратите внимание, что я принял решение, чтобы просто хранить в Caches и мириться с продувкой для пользователей IOS 5.0.

Это одобрено Apple в этом месяце.

Пожалуйста, не копируйте и не вставляйте этот код, не читая и не понимая его в первую очередь - он может быть не совсем точным или оптимизированным, но я надеюсь, что он может помочь кому-то найти решение, которое им поможет.

4
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) 
#include <sys/xattr.h> 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 

//Put this in your method 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSURL *pathURL= [NSURL fileURLWithPath:documentsDirectory]; 

    iOS5 = NO; 
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"5.0.1")) { 
     iOS5 = YES; 
    } 

    // Set do not backup attribute to whole folder 
    if (iOS5) { 
     BOOL success = [self addSkipBackupAttributeToItemAtURL:pathURL]; 
     if (success) 
      NSLog(@"Marked %@", pathURL); 
     else 
      NSLog(@"Can't marked %@", pathURL); 
    } 
} 

- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL 
{ 
    const char* filePath = [[URL path] fileSystemRepresentation]; 
    const char* attrName = "com.apple.MobileBackup"; 
    u_int8_t attrValue = 1; 
    int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0); 
    return result == 0; 
} 
+0

Спасибо за ответ - код отступа BTW с 4 пробелами, чтобы отформатировать его правильно. Вы говорите, что я должен установить атрибут для всей папки документов? Это точный метод, который я использую, за исключением того, что я применяю его к файлу. – colincameron

+0

Он говорит, что он попробовал флаг «не поддерживать». –

+0

Также .. этот код не поддерживает 5.1 и выше. Вы должны использовать этот метод только для установки атрибута в 5.0.1. – badweasel

0

Я смотрел на это и нашел эту очень интересную статью на тему: http://iphoneincubator.com/blog/data-management/local-file-storage-in-ios-5

Я считаю, что вы будете продолжать быть отклонены, если вы пытаетесь использовать папку/Documents для хранения ваш файл DB.

Я предлагаю вам укусить пулю и использовать/Кэш. В худшем случае сценарий для пользователей будет заключаться в том, что их устройство мало работает в памяти, и приложение очищается, удаляя файл DB. В этом случае, когда ваше приложение запускается снова, оно должно скопировать через связанный файл DB в/Cache, и пользователь будет синхронизироваться, чтобы перейти и захватить лишние данные с вашего удаленного сервера. Это предполагает, что это работает ваше приложение.

Чтобы получить приложение, чтобы переместить файл базы данных из/документов в/Cache, вы можете просто сказать NSFileManager, чтобы сделать это для вас ...

#define FILE_MANAGER  [NSFileManager defaultManager] 
#define DOCUMENTS_PATH [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0] 
#define CACHES_PATH  [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex: 0] 
#define DB_DOCS_PATH  [DOCUMENTS_PATH stringByAppendingPathComponent: @"database.db"] 
#define DB_PATH   [CACHES_PATH stringByAppendingPathComponent: @"database.db"] 

if([FILE_MANAGER moveItemAtPath: DB_DOCS_PATH toPath:DB_PATH error:&error]) 
    { 
     NSLog(@"SUCCESSFULLY MOVED %@ to %@",DB_DOCS_PATH,DB_PATH); 
    } 

Это позволит предотвратить существующие пользователям использовать их хранения ICloud без необходимости.

+0

Я заметил, что SDK Google Analytics iOS также скопировал свой файл sql в папку/Documents, поэтому я посмотрел, было ли обновление. Был ... http: //feeds.feedburner.com/ga-dev-changelog-collection-ios Теперь они сохраняются в/Library, а не в папке/Caches, а только в корне. –

+0

К сожалению потеря данных не является вариантом для моего приложения. Приложение поставляется с несколькими листами нот/аккордов, и пользователь может создавать плейлисты из них для исполнения. Эти плейлисты могут быть сохранены и вызваны позже, поэтому я не хочу, чтобы данные были удалены. – colincameron

+0

- это все, что они сохраняют на устройстве, или синхронизируются с удаленным сервером? Если вы этого не сделаете, я бы все равно подумал. Проверьте Parse.com как вариант для этого. Затем вы можете безопасно очистить кеш и повторно синхронизировать его с удаленного сервера. –

1

Вы сказали, что не используете iCloud. В этом случае вам нужно просто переместить файл sqlite в каталог с суффиксом .nosync. Это должно сделать это!

NSString *dataFileName = @"my.sqlite"; 
NSString *dataFileDirectoryName = @"Data.nosync"; 
NSString *documentsDirectoryPath = [self applicationDocumentsDirectory]; 
NSFileManager *fileManager = [NSFileManager defaultManager]; 

if ([fileManager fileExistsAtPath:[documentsDirectoryPath stringByAppendingPathComponent:dataFileDirectoryName]] == NO) { 
    NSError *fileSystemError; 
    [fileManager createDirectoryAtPath:[documentsDirectoryPath stringByAppendingPathComponent:dataFileDirectoryName] 
      withIntermediateDirectories:YES 
    attributes:nil 
     error:&fileSystemError]; 

    if (fileSystemError != nil) { 
     NSLog(@"Error creating database directory %@", fileSystemError); 
    } 
} 

NSString *dataFilePath = [[documentsDirectoryPath 
          stringByAppendingPathComponent:dataFileDirectoryName] 
          stringByAppendingPathComponent:dataFileName]; 

// Move your file at dataFilePath location! 

HTH.

+0

Спасибо за предложение. Можете ли вы указать мне на документацию для суффикса '.nosync'? Я этого раньше не слышал. – colincameron

+1

В разделе «Использование основных данных с примечаниями к выпуску iCloud» ознакомьтесь с разделом «Руководство для приложений в стиле библиотеки». http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html – Mustafa

+0

Это звучит как ваш ответ на меня. – badweasel

Смежные вопросы