如何获得XMLparsing的图像到数组中,并使用iPhone SDK的所有视图控制器中的数组

我有一个URL中的XML文件,我可以parsing数据并从XML文件中获取图像。 但我不知道如何使用其他视图控制器中的图像。 我有一个想法将图像存储在数组中,但是如何在其他视图控制器中使用图像数组。 是否有可能存储在数组中的XMLparsing图像。我正确parsingXML? 请告诉我一个想法。

我的XMLparsing器

//egsBase.h #import <Foundation/Foundation.h> @interface egsBase : NSObject{ IBOutlet UIImage *img; } @property(nonatomic,retain) IBOutlet UIImage *img; @end //egsBase.m #import "egsBase.h" @implementation egsBase @synthesize img; @end //egsXMLParser.h #import <Foundation/Foundation.h> #import "egsBase.h" @interface egsXMLParser : NSObject <NSXMLParserDelegate>{ NSMutableString *currentNodeContent; NSMutableArray *tweets; NSXMLParser *parser; egsBase *currentTweet; } @property(nonatomic,readonly) NSMutableArray *tweets; -(id) loadXMLByURL:(NSString *) urlString; @end //egsXMLParser.m #import "egsXMLParser.h" @implementation egsXMLParser @synthesize tweets; -(id) loadXMLByURL:(NSString *)urlString{ tweets = [[NSMutableArray alloc] init]; NSURL *url = [NSURL URLWithString:urlString]; NSData *data = [[NSData alloc] initWithContentsOfURL:url]; parser = [[NSXMLParser alloc] initWithData:data]; parser.delegate = self; [parser parse]; return self; } -(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { if([elementName isEqualToString:@"Products"]){ currentTweet = [egsBase alloc]; } } -(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if([elementName isEqualToString:@"img"]) { currentTweet.img=[UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString:currentNodeContent]]]; [tweets addObject:currentTweet.img]; } } - (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; } @end 

你parsing正确吗? 有很多问题,一些实质性的,一些更具风格的。 首先,几个实质性的意见:

  1. foundCharacters假定每个元素只被调用一次。 对于像一个通常是真实的URL的东西,但你不能保证这个事实。 它应该只是将字符附加到一个string中,最后一个string的后续存储和清理应该在didEndElement

  2. 你发现的foundCharacter也存储结果,无论你是否检索你关心的元素的数据(更糟糕的是,元素之间的字符)。 如果您在didStartElementdidEndElement之间存储您关心的元素名称, didEndElement存储foundCharacter结果。

  3. 你的didStartElement正在执行alloc ,但是它也没有执行init 。 你应该总是在同一时间做init 。 您也可以稍后再做其他属性设置,但不要忽略调用适当的init方法。

  4. 您的didEndElement正在从服务器检索图像。 你真的应该限制数据检索到XML本身(例如,在图像的情况下,图像的URL),而不是从服务器检索额外的项目。 当你考虑更复杂的devise时,这是非常重要的,在那里最大限度地减less内存命中和提高用户响应时间,你可能想要使用延迟加载的图像,这意味着你只想从XML中检索URL,并让UI处理如果和当图像被检索。 在您开始进行更复杂的开发时,您会后悔在这里进行图像检索。

  5. 您在didStartElementdidEndElement执行的elementName检查之间存在不平衡。 对于您检索数据的所有元素,您应该平衡调用。 我知道你给了我们一个例子,为了简单起见,你只是从XML中检索一个元素,但在下面的例子中,我假设我们检索了两个元素,平衡这些元素的重要性将变得很明显。

更多的文体观察:

  1. 按照惯例,variables名通常以小写字母开头。 类名通常以大写字母开头。 我假定“EGS”是一个确定的类前缀(例如,你的首字母缩写或你公司的首字母缩略词),在这种情况下,类名可能是EGSBaseEGSParser 。 顺便说一下,我不太喜欢名称EGSBase因为它是一个类,用于捕获特定types的XML数据,但具有通用名称。 要么使用一个像NSMutableDictionary一样的通用数据结构,要么使用一个自定义的类,并给它一个有意义的名字(例如根据您对“产品”的引用,我假设是一个产品,因此我已经将它重命名为EGSProduct下面的例子。)任何你想要的,可以调用它,但如果你使用有意义的属性名称给它一个有意义的名字。

  2. 我注意到你正在定义实例variables来支持你的属性。 虽然这是一年或两年前的惯例,但编译器的最新版本使得这个不必要,甚至是不可取的。 你有什么工作,但它不再被认为是最佳实践,是不明智的(因为你可以用单一的错字,结束了重复的实例variables,并得到非常奇怪的行为)。 底线,不要为您的属性定义实例variables。 让编译器为你做。

  3. 我注意到你已经在egsBase定义了img作为一个IBOutlet ,而我发现你真的不可能把它和Interface Builder中的任何东西联系起来。 首先,它甚至不是一个UIView后代(这是一个UIImage ,而不是UIImageView )。 其次, egsBase本身不是一个您将用于Interface Builder控件的类。 底线,这不是一个界面生成器的出口,所以它只是混淆使用IBOutletimg

  4. 我注意到你正在使用retain 。 如果你正在编写ARC代码,那应该是strong (即使你的目标是iOS 4.3)。 如果你不写ARC代码,你的代码中有其他地方泄漏。

  5. 您正在手动合成您的属性。 你可以做到这一点,但没有必要。 另外,现在最好的做法是让你的属性的实例variables有一个前导下划线。 请注意,如果您省略@synthesize语句,它将为您合成具有前导下划线的实例variables。 在这个领域有一些争论,你应该使用属性(我在下面做过)还是使用实例variables。 我不在乎太多,虽然新兴的公约可能倾向于更广泛地使用财产。 如果使用属性,虽然(a) 不要在初始化器和dealloc方法中使用存取器方法 ; 和(b) 在设置属性时总是使用访问器方法 。

  6. 我注意到你正在定义属性和实例variables(特别是对于parsing器),它们是私有的实现细节。 这里出现的标准是将.h中定义的属性限制为其他类需要访问的属性。 任何属于私有类实现的其他属性通常在.m文件本身的私有类扩展中定义。 这是一件小事,但是如果你观察这种做法,你会发现将来使用你的类更容易,你(或其他开发人员)不会对公共接口的什么部分感到困惑,什么是部分的私人执行。

  7. 我注意到你的loadXMLByURL返回一个指向类本身的指针。 通常只有init对象或创build新对象的类才会返回指向自己的指针。

  8. 你的loadXMLByURL可能应该返回(a)一个指向你构造的NSMutableArray的指针(在错误时返回nil ); 或(b) BOOL成功/失败值。

  9. 对于你的自定义类,比如EGSBase ,写一个description方法是很有用的,所以你可以轻松的NSLog


所以,让我举个例子。 假设您有一个如下所示的XML:

 <Products> <products id="0"> <name>name1</name> <img id="1">http://opentestdrive.com/images/first.png</img> </products> <products id="1"> <name>name2</name> <img id="2">http://opentestdrive.com/images/second.png</img> </products> <products id="2"> <name>name3</name> <img id="3">http://opentestdrive.com/images/img1.png</img> </products> <products id="3"> <name>name4</name> <img id="4">http://opentestdrive.com/images/img2.png</img> <img-subproduct id="0">http://opentestdrive.com/images/img5.png</img-subproduct> <img-subproduct id="1">http://opentestdrive.com/images/img4.png</img-subproduct> </products> <products id="4"> <name>name5</name> <img id="5">http://opentestdrive.com/images/img3.png</img> <img-subproduct id="2">http://opentestdrive.com/images/img3.png</img-subproduct> <img-subproduct id="3">http://opentestdrive.com/images/img2.png</img-subproduct> </products> <products id="5"> <name>name6</name> <img id="6">http://opentestdrive.com/images/img4.png</img> </products> <products id="6"> <name>name7</name> <img id="7">http://opentestdrive.com/images/img5.png</img> </products> </Products> 

那么你的EGSProduct将被定义如下:

 // EGSProduct.h #import <Foundation/Foundation.h> @interface EGSProduct : NSObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *imageUrlString; @property (nonatomic, strong) NSString *imageIdentifier; @property (nonatomic, strong) NSMutableArray *subProducts; @end 

 // EGSProduct.m #import "EGSProduct.h" @implementation EGSProduct - (NSString *)description { NSMutableString *result = [NSMutableString stringWithFormat:@"<EGSProduct %p; name='%@'; imageIdentifier='%@'; imageUrlString='%@'; subProducts=", self, self.name, self.imageIdentifier, self.imageUrlString]; NSMutableArray *subProductDescriptions = [NSMutableArray array]; for (EGSProduct *subProduct in self.subProducts) { [subProductDescriptions addObject:[subProduct description]]; } [result appendFormat:@"%@>", [subProductDescriptions componentsJoinedByString:@"; "]]; return result; } @end 

你的parsing器可能看起来像这样:

 // EGSParser.h #import <Foundation/Foundation.h> @interface EGSParser : NSObject @property (nonatomic, strong) NSMutableArray *products; - (BOOL)loadXMLByURL:(NSURL *)url; @end 

 // EGSParser.m #import "EGSParser.h" #import "EGSProduct.h" @interface EGSParser () <NSXMLParserDelegate> @property (nonatomic, strong) NSXMLParser *parser; @property (nonatomic, strong) NSMutableString *currentElementContent; @property (nonatomic, strong) EGSProduct *currentProduct; @property (nonatomic, strong) EGSProduct *currentSubProduct; @end @implementation EGSParser - (BOOL)loadXMLByURL:(NSURL *)url { self.parser = [[NSXMLParser alloc] initWithContentsOfURL:url]; self.parser.delegate = self; return [self.parser parse]; } #pragma mark - NSXMLParser - (void)parserDidStartDocument:(NSXMLParser *)parser { self.products = [[NSMutableArray alloc] init]; } - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { if ([elementName isEqualToString:@"products"]) { self.currentProduct = [[EGSProduct alloc] init]; self.currentProduct.imageIdentifier = attributeDict[@"id"]; } else if ([elementName isEqualToString:@"img-subproduct"]) { self.currentSubProduct = [[EGSProduct alloc] init]; self.currentSubProduct.imageIdentifier = attributeDict[@"id"]; if (self.currentProduct.subProducts == nil) { self.currentProduct.subProducts = [NSMutableArray array]; } self.currentSubProduct.imageIdentifier = attributeDict[@"id"]; self.currentElementContent = [[NSMutableString alloc] init]; } else if ([elementName isEqualToString:@"name"] || [elementName isEqualToString:@"img"]) { self.currentElementContent = [[NSMutableString alloc] init]; } } - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // note, this construct of checking to see if it's nil is actually not needed // (since sending a message to a nil object, by definition, does nothing) // but I wanted to draw your attention to the fact that we set `currentElementContent` // in `didStartElement` and, after saving it in our class, we set it to nil in // `didEndElement` if (self.currentElementContent != nil) [self.currentElementContent appendString:string]; } - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if ([elementName isEqualToString:@"name"]) { self.currentProduct.name = self.currentElementContent; // save the product name self.currentElementContent = nil; // reset our `currentElementContent` } else if ([elementName isEqualToString:@"img"]) { self.currentProduct.imageUrlString = [self.currentElementContent stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; self.currentElementContent = nil; } else if ([elementName isEqualToString:@"img-subproduct"]) { self.currentSubProduct.imageUrlString = self.currentElementContent; self.currentElementContent = nil; [self.currentProduct.subProducts addObject:self.currentSubProduct]; self.currentSubProduct = nil; } else if ([elementName isEqualToString:@"products"]) { [self.products addObject:self.currentProduct]; self.currentProduct = nil; } } @end 

要使用这个类,你可以做如下的事情。 如果想在parsing器完成之后继续使用XML结果(并且超出范围),那么只需要一个类属性(在下面的示例中, xmlProductsResults 。如果希望可以访问各种不同的视图控制器,您可以将此模型数据保存在某个共享类(例如,模型单例)中,您的应用程序委托的属性,或者将其作为参数从视图控制器传递到视图控制器。

 NSURL *url = [NSURL URLWithString:@"http://opentestdrive.com/Products.xml"]; EGSParser *parser = [[EGSParser alloc] init]; if ([parser loadXMLByURL:url]) { NSLog(@"success; products=%@", parser.products); self.xmlProductsResults = parser.products; } else { NSLog(@"fail"); } 

你可以用你的parsing器做更多的事情(比较可靠的XML文件validation,报告错误(如果有的话),等等)。 就我个人而言,我已经做了足够的XMLparsing,现在我使用了一个非常通用的parsing器,它可以parsing我正在处理的大部分XML文件,享受parsing器类的最大限度的重用,但是这是一个很远的桥梁这个对话。 我在这个讨论中已经走得太远了。