سؤال

لقد قمت بإنشاء تطبيق قائمة ودعمه مع البيانات الأساسية.

أرغب في الحصول على قائمة افتراضية عن عناصر 10 مطار 10، بحيث لا يجب أن يبدأ المستخدم من الصفر.

هل هناك أي طريقة للقيام بذلك؟

أي مساعدة موضع تقدير. شكرا مقدما.

هل كانت مفيدة؟

المحلول

هذه هي أفضل طريقة (ولا تتطلب معرفة SQL):
قم بإنشاء تطبيق iPhone Data iPhone Quick Core (أو حتى Mac) باستخدام نفس نموذج كائن مثل تطبيق القائم. اكتب بضعة أسطر من التعليمات البرمجية لحفظ الكائنات المدارة الافتراضية التي تريدها المتجر. ثم، تشغيل هذا التطبيق في محاكاة. الآن، انتقل إلى ~ / مكتبة / دعم التطبيق / محاكاة iPhone / المستخدم / التطبيقات. ابحث عن طلبك بين GUIDs، ثم قم فقط بنسخ متجر SQLite في مجلد مشروع التطبيق الخاص بك.

ثم، قم بتحميل هذا المتجر كما يفعل في مثال Coredatabooks.

نصائح أخرى

نعم هناك في الواقع مثال Coredatabooks هل هذا، يمكنك تنزيل التعليمات البرمجية هنا: عينة من الرموز

ما تفعله هو إنشاء المتجر الداخلي (قاعدة البيانات) باستخدام الإجراء العادي لتهيئة متجرك تماما كما تفعل مع أي متجر آخر، ثم تقوم ببساطة بتشغيل التعليمات البرمجية واتركها تنفيذ التعليمات البرمجية كما هو موضح في مثال Coredatabooks (Snippet رمز أدناه ). بمجرد تهيئة المتجر، سترغب في إنشاء NSManagedObjectContext وتهيئة ذلك مع المتجر المستمر الذي تم إنشاؤه، أدخل جميع الكيانات التي تحتاجها، وحفظ السياق.

بمجرد حفظ السياق بنجاح، يمكنك إيقاف طلبك، ثم انتقل إلى Finder والانتقال إلى المجلد: ~/Library/Developer اكتب البحث في البحث .SQLite و Look Under / Developer، ستمنحك الفرز حسب التاريخ أحدث قاعدة بيانات .sqlite التي يجب أن تتطابق مع الوقت الذي تم تنفيذ التعليمات البرمجية، يمكنك بعد ذلك أخذ هذا المتجر وإضافته كموارد لمشروعك وبعد ثم يمكن قراءة هذا الملف من منسق مخزن مستمر.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator) {
    return persistentStoreCoordinator;
}


NSString *storePath = [[self applicationDocumentsDirectory]      stringByAppendingPathComponent: @"CoreDataBooks.sqlite"];
 /*
  Set up the store.
 For the sake of illustration, provide a pre-populated default store.
 */
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
  NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataBooks"      ofType:@"sqlite"];
 if (defaultStorePath) {
 [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
 }
}

NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber   numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

 NSError *error;
 if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
  // Update to handle the error appropriately.
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 exit(-1);  // Fail
}    

return persistentStoreCoordinator;
}

امل ان يساعد.

-oscar.

مع هذه الطريقة لا تحتاج إلى تقديم تطبيق منفصل أو لديك أي معرفة SQL. تحتاج فقط إلى أن تكون قادرا على إجراء ملف JSON لبياناتك الأولية.

يمكنني استخدام ملف JSON الذي تحليله في الكائنات، ثم أدخلها في البيانات الأساسية. أفعل هذا عند تهيئة التطبيق. أنا أيضا إنشاء كيان واحد في بياناتي الأساسية التي تشير إلى ما إذا كانت هذه البيانات الأولية مدرجة بالفعل، بعد إدراج البيانات الأولية، قمت بتعيين هذا الكيان، لذا في المرة التالية التي يعمل فيها البرنامج النصي، تم بالفعل تهيئة البيانات الأولية بالفعل.

لقراءة ملف JSON إلى كائنات:

NSString *initialDataFile = [[NSBundle mainBundle] pathForResource:@"InitialData" ofType:@"json"];
NSError *readJsonError = nil;
NSArray *initialData = [NSJSONSerialization
                        JSONObjectWithData:[NSData dataWithContentsOfFile:initialDataFile]
                        options:kNilOptions
                        error:&readJsonError];

if(!initialData) {
    NSLog(@"Could not read JSON file: %@", readJsonError);
    abort();
}

ثم يمكنك جعل كائنات الكيان لذلك مثل هذا:

[initialData enumerateObjectsUsingBlock:^(id objData, NSUInteger idx, BOOL *stop) {

    MyEntityObject *obj = [NSEntityDescription
                          insertNewObjectForEntityForName:@"MyEntity"
                          inManagedObjectContext:dataController.managedObjectContext];

    obj.name = [objData objectForKey:@"name"];
    obj.description = [objData objectForKey:@"description"];

    // then insert 'obj' into Core Data

}];

إذا كنت تريد وصفا أكثر تفصيلا حول كيفية القيام بذلك، تحقق من هذا البرنامج التعليمي:http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated.

لمدة 10 عناصر، يمكنك فقط القيام بذلك داخل applicationDidFinishLaunching: في مندوب التطبيق الخاص بك.

تحديد طريقة، قل insertPredefinedObjects, ، الذي يخلق ويمتليم مثيلات الكيان المسؤول عن إدارة عناصر المطار الخاصة بك، وحفظ سياقك. يمكنك إما قراءة السمات من ملف أو ببساطة تشغيلها في التعليمات البرمجية الخاصة بك. ثم، اتصل بهذه الطريقة في الداخل applicationDidFinishLaunching:.

ضع في اعتبارك، عند اتباع رمز مثال Coredatabooks، أنه ربما يكسر إرشادات تخزين بيانات iOS:

https:/developer.apple.com/icloud/documentation/data-storage/

لقد تم رفض تطبيق لنسخ قاعدة البيانات (للقراءة فقط) قاعدة البيانات المسبقة مسبقا إلى دليل المستندات - كما يتم نسخها احتياطيا إلى ICLOUD - وتجعل Apple فقط أن تحدث الملفات التي تم إنشاؤها من قبل المستخدم.

تقدم المبادئ التوجيهية أعلاه بعض الحلول، لكنهم يغليون معظمهم من:

  • قم بتخزين DB في دليل التخزين المؤقت، ومتعامل مع المواقف التي يقوم بها نظام التشغيل الذي يقوم بتطهير التخزين المؤقت - سيتعين عليك إعادة بناء DB، والتي ربما تحكمها معظمنا.

  • قم بتعيين "عدم استخدام ذاكرة التخزين المؤقت" على ملف DB، وهو القليل من القليل، حيث يجب القيام به بشكل مختلف عن إصدارات نظام التشغيل المختلفة.

لا أعتقد أنه من الصعب للغاية، ولكن كن على علم بوجود ما عليك فعله قليلا للقيام بعمل هذا التعليمات البرمجية إلى جانب ICLOUD ...

لذلك قمت بتطوير طريقة عامة يتم تحميلها من قاموس (ربما من JSON) ويمتبأ قاعدة البيانات. يجب استخدامها فقط مع البيانات الموثوقة (من قناة آمنة)، لا يمكن التعامل مع المراجع الدائرية ويمكن أن تكون هجرات المخططات مشكلة ... ولكن بالنسبة لحالات الاستخدام البسيطة مثل الألغام يجب أن تكون على ما يرام

من هنا تبدأ

- (void)populateDBWithDict:(NSDictionary*)dict
               withContext:(NSManagedObjectContext*)context
{
    for (NSString* entitieName in dict) {

        for (NSDictionary* objDict in dict[entitieName]) {

            NSManagedObject* obj = [NSEntityDescription insertNewObjectForEntityForName:entitieName inManagedObjectContext:context];
            for (NSString* fieldName in objDict) {

                NSString* attName, *relatedClass, *relatedClassKey;

                if ([fieldName rangeOfString:@">"].location == NSNotFound) {
                    //Normal attribute
                    attName = fieldName; relatedClass=nil; relatedClassKey=nil;
                } else {
                    NSArray* strComponents = [fieldName componentsSeparatedByString:@">"];
                    attName = (NSString*)strComponents[0];
                    relatedClass = (NSString*)strComponents[1];
                    relatedClassKey = (NSString*)strComponents[2];
                }
                SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", attName ]);
                NSMethodSignature* signature = [obj methodSignatureForSelector:selector];
                NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
                [invocation setTarget:obj];
                [invocation setSelector:selector];

                //Lets set the argument
                if (relatedClass) {
                    //It is a relationship
                    //Fetch the object
                    NSFetchRequest* query = [NSFetchRequest fetchRequestWithEntityName:relatedClass];
                    query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:relatedClassKey ascending:YES]];
                    query.predicate = [NSPredicate predicateWithFormat:@"%K = %@", relatedClassKey, objDict[fieldName]];

                    NSError* error = nil;
                    NSArray* matches = [context executeFetchRequest:query error:&error];


                    if ([matches count] == 1) {
                        NSManagedObject* relatedObject = [matches lastObject];
                        [invocation setArgument:&relatedObject atIndex:2];
                    } else {
                        NSLog(@"Error! %@ = %@ (count: %d)", relatedClassKey,objDict[fieldName],[matches count]);
                    }


                } else if ([objDict[fieldName] isKindOfClass:[NSString class]]) {

                    //It is NSString
                    NSString* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];
                } else if ([objDict[fieldName] isKindOfClass:[NSNumber class]]) {

                    //It is NSNumber, get the type
                    NSNumber* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];

                }
                [invocation invoke];


            }

            NSError *error;
            if (![context save:&error]) {
                NSLog(@"%@",[error description]);
            }
        }
    }   
}

و الأحمال من json ...

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"initialDB" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];

NSError* error;
NSDictionary *initialDBDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                           options:NSJSONReadingMutableContainers error:&error];

[ self populateDBWithDict:initialDBDict withContext: [self managedObjectContext]];

أمثلة JSON.

    {
    "EntitieA": [ {"Att1": 1 }, {"Att1": 2} ],
    "EntitieB": [ {"Easy":"AS ABC", "Aref>EntitieA>Att1": 1} ]
    }

و

{
    "Country": [{"Code": 55, "Name": "Brasil","Acronym": "BR"}],
    "Region": [{"Country>Country>code": 55, "Code": 11, "Name": "Sao Paulo"},
               {"Country>Country>code": 55, "Code": 31, "Name": "Belo Horizonte"}]
}

ماذا عن التحقق مما إذا كانت هناك أي كائنات موجودة وإذا لم يكن كذلك، فقم بإنشاء واحدة مع بعض البيانات؟

NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Settings"];
_managedObjectSettings = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];

if ([_managedObjectSettings count] == 0) {
    // first time, create some defaults
    NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:@"Settings" inManagedObjectContext:managedObjectContext];

    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"speed"];
    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"sound"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey:@"aspect"];
    [newDevice setValue:[NSNumber numberWithBool: NO  ] forKey: @"useH264"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey: @"useThumbnail"];

    NSError *error = nil;
    // Save the object to persistent store
    if (![managedObjectContext save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
}

هذه الإجابة هي فقط للأشخاص الذين هم

  • بما في ذلك قاعدة بيانات مسبقة المكتظة بالسكان في تطبيقك
  • إجراء تطبيق لعدة منصات (iOS، Android، إلخ)

لقد قمت بإجراء قاعدة بيانات SQLite Prepopulated للحصول على تطبيق Android. ثم عندما أقوم بإصدار إصدار iOS من التطبيق، اعتقدت أنه سيكون من الأفضل استخدام البيانات الأساسية. لذلك قضيت البيانات الأساسية وقتا طويلا، ثم أعد كتابة التعليمات البرمجية لإعادة إعداد قاعدة البيانات. تعلم كيفية القيام بكل خطوة واحدة في كلا النظامين يتطلب الكثير من البحث والمحاكمة والخطأ. كان هناك تداخل أقل بكثير مما كنت آمل.

في النهاية قررت فقط استخدام قاعدة بيانات SQLite نفسها من مشروع Android الخاص بي. ثم استخدمت غلاف FMDB للوصول مباشرة إلى قاعدة البيانات في نظام التشغيل iOS. الفوائد:

  • تحتاج فقط إلى جعل قاعدة البيانات preppulted مرة واحدة.
  • لا يحتاج إلى تحول النموذج. بناء الجملة بين Android و FMDB، في حين أن مختلفا، لا يزال متشابها إلى حد ما.
  • لديك الكثير من السيطرة على كيفية إجراء الاستعلامات.
  • يسمح البحث النص الكامل.

على الرغم من أنني لا أسدم في تعلم البيانات الأساسية، إلا أنني كنت أقوم بذلك، فقد أنقذت الكثير من الوقت عن طريق التمسك فقط ب SQLite.

إذا كنت تبدأ في نظام التشغيل iOS ثم التخطيط للانتقال إلى Android، فلا يزال يمكنني استخدام غلاف SQLite مثل FMDB أو بعض البرامج الأخرى لإعداد قاعدة البيانات. على الرغم من أنه يمكنك استخراج قاعدة بيانات SQLite تقنيا التي تقوم بإعدادها مع البيانات الأساسية، فسيتم تسمية المخطط (أسماء الجدول والأعمدة، وما إلى ذلك) بشكل غريب.

بالمناسبة، إذا لم تكن بحاجة إلى تعديل قاعدة بيانات Prepologult الخاصة بك، فلا نسخها إلى دليل المستندات بعد تثبيت التطبيق. فقط الوصول إليها مباشرة من الحزمة.

// get url reference to databaseName.sqlite in the bundle
let databaseURL: NSURL = NSBundle.mainBundle().URLForResource("databaseName", withExtension: "sqlite")!

// convert the url to a path so that FMDB can use it
let database = FMDatabase(path: databaseURL.path)

هذا يجعلها لا تملك نسختين.

تحديث

أنا الآن أستخدم sqlit.swift. بدلا من FMDB، لأنها تدمج بشكل أفضل مع مشاريع SWIFT.

تم العثور على طريقة أخرى لتخزين الإعدادات الافتراضية عن طريق NSUserDefaults. (مفاجأة!) وسهلة.

اقترح بعضها، وضع ذلك في applicationDidFinishLaunching

في حالة معينة من 10 افتراضي، Airport0 من خلال 9

ضبط

NSUserDefaults *nud = [NSUserDefaults standardUserDefaults];
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport0"];
    ...
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport9"];
[nud synchronize];

أو

[[NSUserDefaults standardUserDefaults] setString:@"MACADDRESSORWHY" forKey:@"Airport9"]];
     ...
[[NSUserDefaults standardUserDefaults] synchronize];

ثم، الحصول على الإعدادات الافتراضية.

NSString *air0 = [[NSUserDefaults standardUserDefaults] stringForKey:@"Airport0"];

هذا عملت بالنسبة لي. هذا هو تعديل هذا إجابه بواسطة أندريا توسو ومستوحاة من هذا مقالات. وبعد المشكلة الوحيدة مع الإجابة هي أن هناك فرصة لفقدان البيانات عند نقل ملفات SQLite مع FileManager. لقد قمت بحفظها حوالي 500 صف صفوف باستخدام ReplacePersistentStore بدلا من filemanager.default.copyitem

الخطوة 1
ملء البيانات الأساسية الخاصة بك في تطبيق آخر واحصل على مسار الملفات باستخدام هذا الرمز:

let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
print(documentsDirectory)

الخطوة 2
اسحب 3 ملفات الخاصة بك مع ملحق .sqlite في مشروع Xcode الخاص بك. (تأكد من تحديد إضافة إضافة إلى أهداف).

الخطوه 3
إنشاء وظيفة للتحقق من تشغيل التطبيق الأول في AppDelegate.swift

func isFirstLaunch() -> Bool {
    let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
    let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
    if (isFirstLaunch) {
        UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
        UserDefaults.standard.synchronize()
    }
    return isFirstLaunch
}

Step4.
انسخ هذه الوظيفة في appdelegate.swift للحصول على عنوان URL حيث يجب نقل قاعدة بيانات SQLite:

func getDocumentsDirectory()-> URL {
    let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

الخطوة 5.
استبدال إعلان persistentcontainer مع هذا واحد:

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "ProjectName")

    let storeUrl = self.getDocumentsDirectory().appendingPathComponent("FileName.sqlite")

    if UserDefaults.isFirstLaunch() {
        let seededDataUrl = Bundle.main.url(forResource: "FileName", withExtension: "sqlite")
        try! container.persistentStoreCoordinator.replacePersistentStore(at: storeUrl, destinationOptions: nil, withPersistentStoreFrom: seededDataUrl!, sourceOptions: nil, ofType: NSSQLiteStoreType)
    }

    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top