NSMutableDictionary不会添加到NSMutableArray中

Tam*_*Tam 2 iphone objective-c

我无法使用此代码填充previewData NSMutableArray.XML请求已成功检索,解析但我无法填充tableviewController的previewData数组.

PreviewsController.h代码:

#import <UIKit/UIKit.h>

@interface PreviewsController : UIViewController 
    <UITableViewDelegate, UITableViewDataSource>
{
    UITableView *previewList;
    NSString *enteredUsername;
    NSString *enteredPassword;
    NSMutableString *current_xml_element;
    NSMutableString *current_xml_value;
    NSMutableDictionary *item;
    NSMutableArray *previewData;
}

@property (nonatomic, retain) IBOutlet UITableView *previewList;
@property (nonatomic, retain) NSString *enteredUsername;
@property (nonatomic, retain) NSString *enteredPassword;
@property (nonatomic, retain) NSMutableString *current_xml_element;
@property (nonatomic, retain) NSMutableString *current_xml_value;
@property (nonatomic, retain) NSMutableArray *previewData;
@property (nonatomic, retain) NSMutableDictionary *item;

@end
Run Code Online (Sandbox Code Playgroud)

PreviewsController.m代码:

#import "PreviewsController.h"

@implementation PreviewsController

@synthesize previewList;
@synthesize enteredUsername, enteredPassword;
@synthesize current_xml_element, previewData, item, current_xml_value;

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.previewData = nil;

    [super viewDidUnload];
}

- (void)dealloc {
    [item release];
    [previewData release];
    [enteredUsername release];
    [enteredPassword release];
    [current_xml_element release];
    [super dealloc];
}

- (void)viewDidLoad {
    previewData = [[NSMutableArray alloc] init];

    // Fetch the XML output from API - Start
    NSString *APIURL = [[NSString alloc] initWithFormat:@"http://mysite.com/api/%@/%@", enteredUsername, enteredPassword];
    NSURL *url = [[NSURL alloc] initWithString:APIURL];
    NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    [APIURL release];
    [url release];

    [xmlParser setDelegate:self];
    [xmlParser parse];
    // Fetch the XML output from API - End

    [super viewDidLoad];
}

#pragma mark -
#pragma mark XML Request Methods

-(void)parserDidStartDocument:(NSXMLParser *)parser {
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    current_xml_element = [elementName copy];

    if ([elementName isEqualToString:@"subject"]) {
        item = [[[NSMutableDictionary alloc] init] autorelease];
        current_xml_value = [[NSMutableString alloc] init];
    }
}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if ([current_xml_element isEqualToString:@"subject"]) {
        [current_xml_value appendString:string];
    }
}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"subject"]) {
        [item setObject:current_xml_value forKey:@"subject"];
        [previewData addObject:[item copy]];
//      NSLog(@"array count: %@", [previewData count]);
    }
}

-(void)parserDidEndDocument:(NSXMLParser *)parser {
}

-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
    NSLog(@"Error occurred: %d - %@", [parseError code], [parseError localizedDescription]);
}

#pragma mark -
#pragma mark Table View Data Source Methods

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return [previewData count];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];

    }
    NSUInteger row = [indexPath row];
    cell.textLabel.text = [previewData objectAtIndex:row];
    return cell;
}


@end
Run Code Online (Sandbox Code Playgroud)

当我构建并运行此代码时,在控制台中返回以下错误:

2009-10-15 23:13:55.296 PreviewMyEmail[29964:207] *** -[NSCFDictionary isEqualToString:]: unrecognized selector sent to instance 0x3839a60
2009-10-15 23:13:55.298 PreviewMyEmail[29964:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFDictionary isEqualToString:]: unrecognized selector sent to instance 0x3839a60'
2009-10-15 23:13:55.298 PreviewMyEmail[29964:207] Stack: (
    29307995,
    2531364681,
    29689915,
    29259382,
    29112002,
    3812419,
    13553,
    3063392,
    3029655,
    3106211,
    3070291,
    55820976,
    55820399,
    55818438,
    55817530,
    55851064,
    29094482,
    29091423,
    29088840,
    37398413,
    37398610,
    2781187,
    8436,
    8290
)
Run Code Online (Sandbox Code Playgroud)

我哪里做错了?感谢你的帮助.

干杯.

Col*_*son 7

previewData是否正在其他地方初始化?在给定代码和输出的情况下,它看起来像它没有值.[previewData count]将返回nil,这是0.添加previewData = [[NSMutableArray alloc] init];在开头,它应该工作.


out*_*tis 5

可能会生成错误-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath,尤其是行:

cell.textLabel.text = [previewData objectAtIndex:row];
Run Code Online (Sandbox Code Playgroud)

在这里,您将NSMutableDictionary分配给类型为NSString的属性.应用程序的开发版本应该显示堆栈跟踪中的方法名称和行号.

与错误无关的注释

效率

由于NS集合类保留了对象,因此item除非需要不可变对象,否则不需要存储副本而不是原始副本.

内存泄漏

如果存在多个"subject"元素,则一些复制的对象将产生内存泄漏.您可以自己处理版本或使用属性.属性更容易处理,因此更不容易出错.如果您不打算使用它们,为什么还要定义属性呢?某些属性不是公共接口的一部分,并且该类看起来不适用于库.如果您希望自己释放句柄,请记住在一个方法中使用自动/释放来平衡alloc/copy/retain.对于解析器:didStartElement:...,相应的方法是解析器:didEndElement:...我仍然试图制定一种描述这种平衡的简洁方法(即将推出到你附近的SO问题).

current_xml_element每次解析器进入一个孩子时都会被破坏.相反,您可以在开始/结束处理"主题"节点时设置/取消设置标志.这将打破,如果一个"主题"节点以往任何时候都包含一个子"主题"节点,但这样的XML文档是病态并导致其他问题(例如重挫itemcurrent_xml_value,从而导致内存泄漏).标志的替代方法是存储一堆元素,在didStartElement期间推送并在didEndElement期间弹出.

PreviewsController.h:

@interface PreviewsController : UIViewController 
    <UITableViewDelegate, UITableViewDataSource>
{
    ...
    /* NSMutableString *current_xml_element; */
    BOOL current_element_is_subject;
    ...
}

...
/* @property (nonatomic, retain) NSMutableString *current_xml_element; */
@property (nonatomic, assign) BOOL current_element_is_subject;
...

@end
Run Code Online (Sandbox Code Playgroud)

PreviewsController.m

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {    
    if ([elementName isEqualToString:@"subject"]) {
        self.item = [NSMutableDictionary dictionaryWithCapacity:1];
        self.current_xml_value = [NSMutableString stringWithCapacity:80];
        current_element_is_subject = YES;
    }
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if (current_element_is_subject) {
        [current_xml_value appendString:string];
    }
}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"subject"]) {
        [item setObject:current_xml_value forKey:@"subject"];
        [previewData addObject:item];
        current_element_is_subject = NO;
//      NSLog(@"array count: %@", [previewData count]);
    }
}
Run Code Online (Sandbox Code Playgroud)

博客文章" 让NSXMLParser成为你的朋友 "看起来基本上和你想做的一样.研究它可能会有所帮助.