Загрузить файл XML в отдельном потоке, перезаписать старый и сохранить - PullRequest
1 голос
/ 27 марта 2010

ОБНОВЛЕНИЕ 18.11.2011 Проверьте принятый ответ. Работает и спасает жизнь!

Привет всем ... так что я пытаюсь выяснить, как это сделать. Я пробежался по множеству форумов, чтобы найти ответ, но безуспешно. Либо их процесс слишком сложен для понимания, либо это просто излишество. То, что я пытаюсь сделать, это. У меня есть файл XML в моем приложении. Это 500k XML-файл, который я не хочу, чтобы пользователь ждал при загрузке. ТАК ... Я поместил его в свое приложение, которое убивает время загрузки и делает приложение доступным в автономном режиме. Что я хочу сделать, так это, когда приложение загружается, в фоновом режиме (отдельный поток) загрузить тот же самый XML-файл, который МОЖЕТ быть обновлен новыми данными. Как только файл XML завершен, я хочу заменить файл XML, который использовался для загрузки файла. Любые предложения или подсказки кода будут с благодарностью. Заранее спасибо!

Ответы [ 3 ]

2 голосов
/ 27 марта 2010

Вы можете использовать NSOperation для асинхронной загрузки файла.

Вы можете использовать NSFileManager для сохранения файла в каталоге документов вашего приложения.

Edit:

Вы пытаетесь записать файл в свой пакет приложений. Вы не можете записывать файлы в комплекте - это часть модели изолированной программной среды безопасности Apple.

Вы должны поместить файл в каталог документов вашего приложения и написать туда.

NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectoryPath = [paths objectAtIndex:0];
NSString* filePath = [documentsDirectoryPath stringByAppendingPathComponent:@"myfile.xml"];
0 голосов
/ 19 ноября 2011

В итоге я понял это. Это старый пост, но, похоже, он по-прежнему получает много просмотров, поэтому я решил помочь некоторым людям. Имейте в виду, что этот код НЕ идеален ... есть много способов снять кожу с кошки ... и вот как я снял с нее кожу. Это работает, вот и все, что имеет значение!

В двух словах, как это работает ... Приложение запускает> проверяет, есть ли сохраненная «дата / идентификатор». Это будет в формате «ММДД». Если нет сохраненной даты / идентификатора, она создаст пустую для сравнения позже.

При сравнении, если идентификатор не совпадает, загружается новый файл. Сегодняшняя дата - 18.11.2011, поэтому ID будет «1118». Если вы снова запустите приложение сегодня, идентификаторы совпадут, поэтому приложение будет анализировать локальный XML-файл, а не загружать другой. (для меня это экономит время, мой XML-файл имеет размер 2-4 МБ.)

Этот код будет загружать новый XML-файл ежедневно, ЕСЛИ БЕСПЛАТНО не запускалось приложение в течение дня. Тогда он будет использовать локальный файл.

//////////      applicationDidFinishLaunching     ///////////
lastSyncArray = [[NSMutableArray alloc] initWithCapacity:0];

//check documents directory to see if you have a saved "date/ID" from earlier
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *fullFileNameSavedLastSyncArray = [NSString stringWithFormat:@"%@/lastSyncArray", docDir];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullFileNameSavedLastSyncArray];

if (fileExists == YES) {
    // yes you have a saved "date/ID" from earlier
    NSArray * temp = [[NSArray alloc] init];
    temp = [NSKeyedUnarchiver unarchiveObjectWithFile:fullFileNameSavedLastSyncArray];

    for ( int i=0; i<[temp count]; i++ ){

        [lastSyncArray addObject:[temp objectAtIndex:i]];

    }// end for loop


}
else {

    //insert blank data for comparison later
    [lastSyncArray addObject:@""];
}

[NSThread detachNewThreadSelector:@selector(checkXMLFile) toTarget:self withObject:nil];

/////////// end applicationDidFinishLaunching /////////////




// own function in App Delegate
-(void)checkXMLFile {


    //get current month/day
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:[NSDate date]];
    NSInteger day = [components day];
    NSInteger month = [components month];
    NSString * currentTimeString = [NSString stringWithFormat:@"%d%d",month,day];


    //check if file exists first
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString * fileName = [NSString stringWithFormat:@"inventory.xml"];
    NSString *xmlPath = [documentsDirectory stringByAppendingPathComponent:fileName];
    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:xmlPath];

    if (fileExists == YES) {
        //yes there is a saved xml file
        NSLog(@"There is a saved file from before");

        //compare last sync date and current date. if they mismatch... download new file
        NSString * sToCompare = [[lastSyncArray objectAtIndex:0] description];

        if ([sToCompare compare:currentTimeString]==0) {
            //its a match this has been downloaded today. no need to re download.
        }
        else {

            //clear out old download date and save new
            [lastSyncArray removeAllObjects];

            //save new date         
            [lastSyncArray addObject:currentTimeString];

            // we are downloading a new xml file and saving it
            NSString * pdfURL2 = [NSString stringWithFormat:@"http://myfile.com/inventory.xml"];
            NSString *urlString = pdfURL2;
            NSURL *url = [NSURL URLWithString:urlString];
            NSData * xmlData = [NSData dataWithContentsOfURL:url];

            if (!xmlData) {


            }
            else{
                NSLog(@"EXISTS");
                NSLog(@"Begin to save xml");
                NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
                NSString *documentsDirectory = [paths objectAtIndex:0];
                NSString * fileName = [NSString stringWithFormat:@"inventory.xml"];
                NSLog(@"File to save: %@",fileName);
                NSString *xmlPath = [documentsDirectory stringByAppendingPathComponent:fileName];
                [xmlData writeToFile:xmlPath atomically:YES];
                NSLog(@"XML saved");


            }
        }



    }
    else {
        NSLog(@"MISSING XML");
        //no there is not a saved xml file this must be first load go ahead and download
        NSString * pdfURL2 = [NSString stringWithFormat:@"http://myfile.com/inventory.xml"];
        NSString *urlString = pdfURL2;
        NSURL *url = [NSURL URLWithString:urlString];
        NSData * xmlData = [NSData dataWithContentsOfURL:url];

        if (!xmlData) {


        }
        else{
            NSLog(@"EXISTS");
            NSLog(@"Begin to save xml");
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *documentsDirectory = [paths objectAtIndex:0];
            NSString * fileName = [NSString stringWithFormat:@"inventory.xml"];
            NSLog(@"File to save: %@",fileName);
            NSString *xmlPath = [documentsDirectory stringByAppendingPathComponent:fileName];
            [xmlData writeToFile:xmlPath atomically:YES];
            NSLog(@"XML saved");


        }
    }


    [self sendToParser];


}



- (void)sendToParser{

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];


    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString * fileName = [NSString stringWithFormat:@"inventory.xml"];
    NSString *xmlPath = [documentsDirectory stringByAppendingPathComponent:fileName];

    [self parseXMLFileAtURL:xmlPath];

    [pool release];

}


- (void)parseXMLFileAtURL:(NSString *)URL //URL is the file path (i.e. /Applications/MyExample.app/MyFile.xml)
{   
    //you must then convert the path to a proper NSURL or it won't work
    NSURL *xmlURL = [NSURL fileURLWithPath:URL];
    NSData * data = [[NSData alloc] init];
    data = [NSData dataWithContentsOfURL:xmlURL];

    // here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
    // this may be necessary only for the toolchain
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

    // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
    [parser setDelegate:self];

    // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
    [parser setShouldProcessNamespaces:NO];
    [parser setShouldReportNamespacePrefixes:NO];
    [parser setShouldResolveExternalEntities:NO];

    [parser parse];

    [parser release];
}




- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespace qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{

    //your code here
    return;

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    //your code here
}


- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespace qualifiedName:(NSString *)qName
{
    //your code here
    return;
}


- (void)parserDidEndDocument:(NSXMLParser *)parser{
    //your code here

}






//////////   application will terminate    /////////////
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *fullFileNameSavedLastSyncArray = [NSString stringWithFormat:@"%@/lastSyncArray", docDir];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL fileExists fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullFileNameSavedLastSyncArray];

//check to see we have a last sync array
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullFileNameSavedLastSyncArray];
if (fileExists == YES) {
    //file exists delete it so we can recreate it here in a sec
    [fileManager removeItemAtPath:fullFileNameSavedLastSyncArray error:NULL];
}
if ([lastSyncArray count] >=1) {
    [NSKeyedArchiver archiveRootObject:lastSyncArray toFile:fullFileNameSavedLastSyncArray];
}


////// end application will terminate ///////////
0 голосов
/ 31 марта 2010

У вас есть контроль над XML на сервере? Вместо загрузки файла XML, независимо от того, отличается он или нет, создайте подпись SHA1 для файла и сравните его с подписью SHA1 для файла, который вы уже кэшировали.

Если подписи одинаковы, нет необходимости обременять пользователя второй, бессмысленной загрузкой (особенно в сетях WWAN). Если подписи отличаются, только тогда вы можете запустить запрос на загрузку в фоновом режиме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...