问题描述
我无法用此代码填充previewData NSMutableArray.XML请求已成功检索,解析,但无法填充tableviewController的PreviewData数组.
I am unable to populate the previewData NSMutableArray with this code. XML request is successfully retrieved, parsed but I am unable to populate the previewData array for tableviewController.
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
构建并运行此代码时,控制台中将返回以下错误:
When I build and run this code, the following error is returned in console:
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
)
我在哪里做错了?感谢您的所有帮助.
Where am I doing wrong? Thanks for all your help.
干杯.
推荐答案
错误可能在-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
中生成,特别是这一行:
The error might be generated in -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
, in particular the line:
cell.textLabel.text = [previewData objectAtIndex:row];
在这里,您正在将NSMutableDictionary分配给类型为NSString的属性.应用的开发版本应在堆栈跟踪中显示方法名称和行号.
Here you're assigning an NSMutableDictionary to a property with type NSString. A development version of your app should show you the method name and line number in the stack trace.
由于NS集合类保留对象,因此不需要存储 item
的副本而不是原始副本,除非您想要一个不可变的对象.
Since the NS collection classes retain objects, there's no need to store a copy of item
rather than the original, unless you want an immutable object.
如果有多个主题"元素,则一些复制的对象将产生内存泄漏.您可以自己处理发布,也可以使用属性.属性更易于处理,因此更不容易出错.如果不打算使用属性,为什么还要麻烦定义它们呢?其中一些属性不是公共接口的一部分,并且该类看起来不是用于库的.如果要处理自己的释放,请记住在一种方法中分配/复制/保留与在相应方法中自动/释放之间取得平衡.对于parser:didStartElement:...,相应的方法是parser:didEndElement:....我仍在尝试以简洁的方式描述这种平衡(即将在).
A few of the copied objects will produce memory leaks if there is more than one "subject" element. You can either handle the release yourself or use properties. Properties are easier to deal with, and thus less error prone. Why bother to define properties if you're not going to use them? Some of the properties aren't part of the public interface, and the class doesn't look to be for a library. If you want handle releasing yourself, remember to balance alloc/copy/retain in one method with auto-/release in a corresponding method. For parser:didStartElement:..., the corresponding method is parser:didEndElement:... I'm still trying to formulate a succinct way of describing this balance (coming soon to an SO question near you).
current_xml_element
都会被破坏.相反,可以在开始/结束处理主题"节点时设置/取消设置标志.如果主题"节点曾经包含一个子主题"节点,则此操作将中断,但是这样的XML文档将是病理性的,并引起其他问题(例如,破坏 item
和 current_xml_value
,从而导致内存泄漏).标志的替代方法是存储元素堆栈,在didStartElement期间压入,在didEndElement期间弹出.
current_xml_element
gets clobbered every time the parser descends into a child. Instead, you can set/unset a flag when you start/end processing a "subject" node. This will break if a "subject" node ever contains a child "subject" node, but such an XML document would be pathological and cause other problems (e.g. clobbering item
and current_xml_value
, thus causing memory leaks). An alternative to a flag is to store a stack of elements, pushing during didStartElement and popping during didEndElement.
PreviewsController.h:
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
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]);
}
}
博客条目"使NSXMLParser成为您的朋友"似乎基本上是在你想要的同样的东西.研究它可能会有所帮助.
The blog entry "Make NSXMLParser your friend" appears to be doing basically the same thing you want. It would probably be helpful to study it.
这篇关于NSMutableDictionary不会添加到NSMutableArray中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!