我无法使用此代码填充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
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
当我构建并运行此代码时,在控制台中返回以下错误:
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
)
我在哪里做错了?谢谢你的帮助。
干杯。
答案 0 :(得分:7)
是否在其他地方初始化了previewData?在给定代码和输出的情况下,它看起来像它没有值。 [previewData count]
将返回nil,即0。在开头添加previewData = [[NSMutableArray alloc] init];
,它应该有效。
答案 1 :(得分:5)
可能会在-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
中生成错误,特别是行:
cell.textLabel.text = [previewData objectAtIndex:row];
在这里,您要将NSMutableDictionary分配给类型为NSString的属性。应用程序的开发版本应该显示堆栈跟踪中的方法名称和行号。
由于NS集合类保留了对象,因此除非需要不可变对象,否则不需要存储item
的副本而不是原始副本。
如果存在多个“subject”元素,则一些复制的对象将产生内存泄漏。您可以自己处理版本或使用属性。属性更容易处理,因此更不容易出错。如果您不打算使用它们,为什么还要定义属性呢?某些属性不是公共接口的一部分,并且该类看起来不适用于库。如果您希望自己释放句柄,请记住在一个方法中使用自动/释放来平衡alloc / copy / retain。对于解析器:didStartElement:...,相应的方法是解析器:didEndElement:...我仍在尝试制定一种描述这种平衡的简洁方法(即将推出an SO question near you)。
每次解析器进入子进程时, current_xml_element
都会被破坏。相反,您可以在开始/结束处理“主题”节点时设置/取消设置标志。如果“主题”节点曾经包含子“主题”节点,这将会中断,但是这样的XML文档将是病态的并导致其他问题(例如,破坏item
和current_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
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]);
}
}
博客条目“Make NSXMLParser your friend”似乎与您想要的基本相同。研究它可能会有所帮助。
答案 2 :(得分:1)
确保初始化previewData
- 如果您从未初始化数组,那么它将是nil
值。在Objective-C中,您可以向nil
发送消息,因此发送addObject:
消息将不会执行任何操作,[nil count]
将返回0.