gpt4 book ai didi

iphone - 如何使用iphone sdk将XML解析的图像放入数组并在所有 View Controller 中使用该数组

转载 作者:行者123 更新时间:2023-12-03 21:02:18 24 4
gpt4 key购买 nike

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

我的XML分析器

//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

最佳答案

您解析正确吗?有很多问题,有些是实质性的,有些是风格上的。首先,一些实质性观察:

  • 您的foundCharacters假定每个元素仅被调用一次。对于通常是真实的URL之类的东西,但您不能保证这一事实。它应该只是将字符附加到字符串,最后字符串的后续存储和清除应在didEndElement中进行。
  • 无论是否要检索您所关心的元素的数据(更糟糕的是,元素之间的字符),您的foundCharacter也会存储结果。仅当您在所关注元素名称的foundCharacterdidStartElement之间时,才存储didEndElement的结果。
  • 您的didStartElement正在执行alloc,但也没有在执行init。您应该始终同时执行init。您也可以稍后进行其他属性设置,但不要忽略调用适当的init方法。
  • 您的didEndElement正在从服务器检索图像。您确实应该将数据检索限制为仅XML本身(例如,对于图像,为图像的URL),而不要从服务器中检索其他项。当您考虑使用更复杂的设计时,这一点尤其重要,在这种设计中,为了最大程度地减少内存占用并改善用户响应时间,您可能希望采用图像的延迟加载,这意味着您只想从XML中检索URL,并让UI处理是否以及何时检索图像。当您将来开始进行更复杂的开发时,您会后悔在这里进行图像检索。
  • 您在elementNamedidStartElement中执行的didEndElement检查之间不平衡。对于要检索其数据的所有元素,应该平衡调用。我知道您给我们提供了一个示例,出于简单起见,您仅从XML检索单个元素,但是在下面的示例中,我假定我们正在检索两个元素,而平衡这些元素的重要性将变得显而易见。

  • 对于更多的风格观察:
  • 按照约定,变量名通常以小写字母开头。类名通常以大写字母开头。我假设“EGS”是已建立的类前缀(例如,您的姓名缩写或公司的缩写),在这种情况下,类名称可能是EGSBaseEGSParser。顺便说一下,我不太喜欢EGSBase,因为它是一个旨在捕获特定类型的XML数据的类,但是具有通用名称。要么使用像NSMutableDictionary这样的通用数据结构,要么使用一个自定义类并为其赋予一个有意义的名称(例如,基于您对“产品”的引用,我假设这是一个产品,因此我在我中将其重命名为EGSProduct)下面的示例。)可以随意调用它,但是如果您使用有意义的属性名称,请给它一个有意义的名称。
  • 我注意到您正在定义实例变量来支持您的属性。尽管在一两年前这是惯例,但最新版本的编译器使这一点变得不必要,甚至不建议这样做。您所拥有的有效,但是不再被认为是最佳实践,并且不建议这样做(因为您可以用一个错字输入,就得到重复的实例变量,并且得到非常奇怪的行为)。最重要的是,不要为属性定义实例变量。让编译器为您执行此操作。
  • 我注意到您已经在img中将egsBase定义为IBOutlet,但是我发现您真的不可能将它链接到Interface Builder中的任何东西。首先,它甚至不是UIView的后代(它是UIImage,而不是UIImageView)。其次,egsBase本身不是您要用于Interface Builder控件的类。最重要的是,这不是Interface Builder的插座,因此使用IBOutlet代替img只是令人困惑。
  • 我注意到您正在使用retain。如果您正在编写ARC代码,则可能应该是strong(即使您的目标是iOS 4.3)。如果您不编写ARC代码,则代码的其他地方会泄漏。
  • 您正在手动合成属性。您可以这样做,但这不是必需的。另外,当今的最佳做法是让媒体资源的实例变量下划线开头。注意,如果省略@synthesize语句,它将为您合成实例变量和前导下划线。该领域是否应使用属性(我在下面做过)还是使用实例变量存在一些争议。我不太在乎,尽管新兴的约定可能倾向于更广泛地使用属性。如果使用属性,则(a)don't use the accessor methods in the initializer and dealloc methods;和(b)always use the accessor methods when setting properties
  • 我注意到您正在定义属性和实例变量(特别是对于解析器),它们是 private 实现细节。这里新兴的标准是将.h中定义的属性限制为其他类将需要访问的属性。通常,在.m文件本身的 private 类扩展中定义了属于 private 实现类的任何其他属性。这是一件小事,但是如果您遵循这种做法,将来会发现使用类更加容易,因为您(或其他开发人员)不会对 public 接口的内容和功能感到困惑 private 执行。
  • 我注意到您的loadXMLByURL返回了指向类本身的指针。通常,只有init对象或创建新对象的类才会返回指向自身的指针。
  • 您的loadXMLByURL应该应该返回(a)指向您构造的NSMutableArray的指针(错误时返回nil);或(b)BOOL成功/失败值。
  • 对于自定义类,例如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

    您的解析器可能看起来像:
    //  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

    要使用此类,您可以执行以下操作。如果您想在解析器完成后继续使用XML结果(并超出范围),则只需要一个class属性(在下面的示例中为 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");
    }

    您可以使用解析器做更多的事情(对格式不正确的XML文件进行更可靠的验证,报告错误(如果有的话),返回等)。就个人而言,我现在已经完成了足够的XML解析,现在我使用了一个非常通用的解析器,该解析器可以在几行中解析我正在处理的大多数XML文件,以最大限度地重用解析器类,但这太过分了这个对话。在这个讨论中,我已经走得太远了。

    关于iphone - 如何使用iphone sdk将XML解析的图像放入数组并在所有 View Controller 中使用该数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14659491/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com