Iphone 在单独的线程上加载XML文件,覆盖旧文件并保存

Iphone 在单独的线程上加载XML文件,覆盖旧文件并保存,iphone,iphone-sdk-3.0,Iphone,Iphone Sdk 3.0,2011年11月18日更新 检查已接受的答案。它工作,它是一个救生圈 大家好。。。所以我想知道怎么做。我在很多论坛上转悠,试图找到我的答案,但没有成功。要么是他们的过程太复杂,我无法理解,要么就是太过份了。我想做的就是这样。我的应用程序中有一个XML文件。这是一个500KXML文件,我不希望用户在加载时必须等待。所以我把它放在我的应用程序中,这样可以缩短加载时间,并使应用程序离线可用。我想做的是,当应用程序加载时,在后台(单独的线程)下载相同的xml文件,该文件可能会用新数据更新。xml文件完成

2011年11月18日更新 检查已接受的答案。它工作,它是一个救生圈


大家好。。。所以我想知道怎么做。我在很多论坛上转悠,试图找到我的答案,但没有成功。要么是他们的过程太复杂,我无法理解,要么就是太过份了。我想做的就是这样。我的应用程序中有一个XML文件。这是一个500KXML文件,我不希望用户在加载时必须等待。所以我把它放在我的应用程序中,这样可以缩短加载时间,并使应用程序离线可用。我想做的是,当应用程序加载时,在后台(单独的线程)下载相同的xml文件,该文件可能会用新数据更新。xml文件完成后,我想替换用于加载该文件的xml文件。如有任何建议或代码提示,将不胜感激。提前谢谢

您可以使用
NSOperation
异步下载文件

您可以使用
NSFileManager
将文件保存到应用程序的文档目录中

编辑:

您正试图写入应用程序包中的文件。您不能写入捆绑包中的任何文件——这是苹果安全沙箱模型的一部分

您应该将文件放在应用程序的Documents目录中,并在那里写入

NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectoryPath = [paths objectAtIndex:0];
NSString* filePath = [documentsDirectoryPath stringByAppendingPathComponent:@"myfile.xml"];

您可以控制服务器上的XML吗?不管XML文件是否不同,都不要下载它,而是对该文件进行SHA1签名,并将其与已缓存文件的SHA1签名进行比较


如果签名是相同的,那么用户就没有必要再进行第二次毫无意义的下载(特别是在WWAN网络上)。如果签名不同,只有这样,你才会在后台发出下载请求。

我最终弄明白了这一点。这是一个老帖子,但它似乎仍然有很多观点,所以我想我会帮助一些人。请记住,此代码并不完美。。。给猫剥皮有很多种方法。。我就是这样剥皮的。它有效,这才是最重要的

简而言之,它的工作原理是。。。 应用程序启动>检查是否有保存的“日期/ID”。其格式为“MMDD”。如果没有保存的日期/ID,它将创建一个空的日期/ID以供以后比较

当它比较id是否不匹配时,它将下载一个新文件。 今天的日期是2011年11月18日,所以ID应该是“1118”。如果您今天再次启动该应用程序,ID将匹配,因此该应用程序将解析本地xml文件,而不是下载另一个。(这对我来说节省了很多时间,我的XML文件是2-4Mbs。)

此代码将每天下载一个新的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 ///////////
///applicationdFinishLaunching///////////
lastSyncArray=[[NSMutableArray alloc]initWithCapacity:0];
//检查文档目录,查看是否保存了以前的“日期/ID”
NSArray*Path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,是);
NSString*docDir=[path objectAtIndex:0];
NSString*fullFileNameSavedLastSyncArray=[NSString stringWithFormat:@“%@/lastSyncArray”,docDir];
BOOL fileExists=[[NSFileManager defaultManager]fileExistsAtPath:fullFileNameSavedLastSyncArray];
如果(fileExists==YES){
//是的,您有一个先前保存的“日期/ID”
NSArray*temp=[[NSArray alloc]init];
temp=[NSKeyedUnarchiver unarchiveObjectWithFile:fullFileNameSavedLastSyncArray];
对于(int i=0;i=1){
[NSKeyedArchiver archiveRootObject:lastSyncArray toFile:fullFileNameSavedLastSyncArray];
}
//////结束应用程序将终止///////////

你的问题到底是什么?如何解析XML文件?如何通过HTTP下载文件?如何使用线程?如何比较两个文件?这里已经有了所有这些问题的答案。你需要问一个更简洁、更具体的问题。谢谢你的回答。我的问题是,如何在单独的线程上下载文件(在后台)并替换应用程序中已经存在的现有文件。就像我说的,我已经看了又看,但找不到合适的答案。谢谢Shaggy,你的建议帮助了我,但我仍然有一个小问题。我已经更新了我的帖子以显示它是什么。