2010-11-08 51 views
2

我已閱讀關於此的帖子,而且看起來很直截了當。一般來說,我對Obj-C和iPhone dev都很陌生,所以我可以很容易地忽略某些東西。我似乎無法將文章對象返回NSMutableArray。我沒有得到任何錯誤,但當我嘗試NSLog()一些東西我得到EXEC_BAD_ACCESS錯誤(我假設內存訪問問題?)。我有一個ArticlesParser的類,它的解析......這裏是什麼樣子:幫助!如何在控制器之間共享NSXMLParser類?

// ArticlesParser.h 
#import <Foundation/Foundation.h> 
#import "Article.h" 

@class Article; 

@interface ArticlesParser : NSObject <NSXMLParserDelegate> { 
NSMutableString *currentCharaters; 
Article *currentArticle; 
NSMutableArray *articlesCollection; 
NSMutableData *xmlData; 
NSURLConnection *connectionInProgress; 
BOOL connectionHasCompleted; 
} 

@property (nonatomic, assign) BOOL connectionHasCompleted; 

- (void)parseUrl:(NSString *)url; 
- (void)beginParsing:(NSURL *)xmlUrl; 
- (NSMutableArray *)arrayOfArticles; 

@end 

這裏的執行...

// ArticlesParser.m 
#import "ArticlesParser.h" 

@implementation ArticlesParser 

@synthesize connectionHasCompleted; 

#pragma mark - 
#pragma mark Parsing methods 

- (void)parseUrl:(NSString *)url 
{ 
[self setConnectionHasCompleted:NO]; 
NSURL *xmlUrl = [NSURL URLWithString:url]; 
[self beginParsing:xmlUrl]; 
} 

- (void)beginParsing:(NSURL *)xmlUrl 
{ 
[articlesCollection removeAllObjects]; 
articlesCollection = [[NSMutableArray alloc] init]; 

NSURLRequest *request = [NSURLRequest requestWithURL:xmlUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30]; 

// clear existing connection if there is one 
if (connectionInProgress) { 
    [connectionInProgress cancel]; 
    [connectionInProgress release]; 
} 

[xmlData release]; 
xmlData = [[NSMutableData alloc] init]; 

// asynchronous connection 
connectionInProgress = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; 
} 

- (NSMutableArray *)arrayOfArticles 
{ 
// NOT RETURNING ANYTHING 
return articlesCollection; 
} 

#pragma mark - 
#pragma mark NSXMLParserDelegate methods 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
[xmlData appendData:data]; 
} 

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 
{ 
if ([elementName isEqual:@"article"]) { 
    currentArticle = [[Article alloc] init]; 
    return; 
} 
if ([elementName isEqual:@"title"]) { 
    currentCharaters = [[NSMutableString alloc] init]; 
    return; 
} 
if ([elementName isEqual:@"last_updated"]) { 
    currentCharaters = [[NSMutableString alloc] init]; 
    return; 
} 
} 

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{ 
[currentCharaters appendString:string]; 
} 

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
{ 
if ([elementName isEqual:@"article"]) { 
    [articlesCollection addObject:currentArticle]; 
    [currentArticle release], currentArticle = nil; 
    return; 
} 
if ([elementName isEqual:@"title"]) { 
    [currentArticle setTitle:currentCharaters]; 
    [currentCharaters release], currentCharaters = nil; 
    return; 
} 
if ([elementName isEqual:@"last_updated"]) { 
    [currentArticle setLastModified:currentCharaters]; 
    [currentCharaters release], currentCharaters = nil; 
    return; 
} 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData]; 
[parser setDelegate:self]; 

[parser parse]; 
[parser release]; 

[self setConnectionHasCompleted:YES]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
[currentArticle release]; 
currentArticle = nil; 

[currentCharaters release]; 
currentCharaters = nil; 

[articlesCollection release]; 
articlesCollection = nil; 

[connectionInProgress release]; 
connectionInProgress = nil; 

[xmlData release]; 
xmlData = nil; 

NSLog(@"connection failed: %@", [error localizedDescription]); 
} 

@end 

我知道,實際的解析工作,因爲我確實有這直接在我的視圖控制器中,一切正常。但是現在我想從另一個控制器訪問基本相同的東西,只有URL是不同的(儘管返回了相同格式的XML)。

這裏是如何,我想利用這個類在我的控制器:

// instance method called within an articles controller 
// that is to load the results in a table view 
- (void)loadArticles 
{ 
    // (leaving off the URL because it's not important) 
NSString *urlToRequest = [NSString stringWithFormat:@"...", [self letterToList]]; 
ArticlesParser *aParser = [[ArticlesParser alloc] init]; 

    // initiate the parsing 
[aParser parseUrl:urlToRequest]; 

    // load up the articles ivar so the tableview can 
    // make use of it to load its cells 
articles = [aParser arrayOfArticles]; 
} 

有沒有辦法,我失去了一些東西明顯?這是分享NSXMLParser代碼的好方法嗎?

我拉我的頭髮在這一個......先謝謝了!

回答

1

它是什麼你想要的NSLog生成的EXEC_BAD_ACCESS錯誤?查看你的代碼,你對arrayOfArticles的調用應該返回一個沒有元素的NSMutableArray,例如像這樣的理解給出一個EXEC_BAD_ACCESS:

NSLog(@"%@", [[articles objectAtIndex:0] description]); // index out of bounds 

通過讓XML解析器類還負責獲取它會(使用NSURLConnection的),你做了它的異步分析數據,這意味着它不再適合使用這樣的:

ArticlesParser *ap = [[[ArticlesParser alloc] init] autorelease]; 
[ap parseURL:@"http://example.com/foo"]; 
NSArray *anArray = [ap arrayOfArticles]; 

anArray現在是一個空數組,只會在未來某個不確定的點進行填充,如果在所有 - 而到那個時候,而不輪詢陣列無法檢測。 Urgh! :)

有幾種方法可以解決這個問題。一種方法是讓XML解析器類聲明委託方法,爲XML數據完全獲取和解析時以及發生錯誤情況時提供回調(與NSURLConnection中委託方法的工作方式大致相同)。另一種方法是讓您的XML解析器類成爲簡單(同步)的XML解析器,並將異步數據獲取代碼移到您的類之外。

+0

在這種情況下,同步呼叫會很好。雖然我不確定如何進行異步調用。 – rpheath 2010-11-08 03:24:32

1

有幾件事我看到一個問題與我的頭頂。

首先,您需要copyretainarrayOfArticles返回,如果您打算繼續使用並稍後使用它。

articles = [[aParser arrayOfArticles] copy]; 

當然,您當然需要確保在適當的時候將其釋放。

其次,因爲它是寫loadArticles居然漏ArticleParser它創建,所以你需要在方法的最後調用[aParser release]

事實上,您必須釋放創建數組的解析器才能保留/複製返回值。一旦ArticlesParser被釋放,它將釋放它的內部articlesCollection並且如果這是最後一個參考,則釋放它。由於您的arrayOfArticles方法將該引用分發給其他人,因此他們需要複製該數組或保留該引用以在創建它的ArticlesParser死後保持活動狀態。

最後,您正在異步下載數據,但您在撥打parseUrl:後立即致電arrayOfArticles。這絕不會導致您獲得任何有用的信息,因爲尚未下載或解析數據。您需要您的ArticlesParser提供某種方式通知感興趣的各方何時完成分析下載的數據,然後他們可以撥打arrayOfArticles來獲取數據。

編輯:應對通知是創建一個委託協議,添加一個委託財產ArticlesParser

的一種方式,已控制器設置本身作爲財產的價值,並有解析器調用委託方法完成後。

例如:

// ArticlesParser.h 
#import <Foundation/Foundation.h> 
#import "Article.h" 

@class Article; 
@class ArticlesParser; 

@protocol ArticlesParserDelegate <NSObject> { 
    - (void)parserDidFinish:(ArticlesParser*)parser; 
    - (void)parser:(ArticlesParser*)parser didFailWithError:(NSError*)error; 
@end 

@interface ArticlesParser : NSObject <NSXMLParserDelegate> { 
    id<ArticlesParserDelegate> delegate; 
    // ... the rest the same ... 
} 
@property (nonatomic, assign) id<ArticlesParserDelegate> delegate; 
// ... the rest the same ... 
@end 

// ArticlesParser.m 
// ... the same as you have, but with this stuff added ... 
@synthesize delegate; 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    // ... same as you have, add this at end... 
    [delegate parserDidFinish:self]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    // ... same as you have, add this at end... 
    [delegate parser:self didFailWithError:error]; 
} 
+0

謝謝,認真清理了很多。我使用上面描述的代表團工作。真棒! – rpheath 2010-11-08 14:44:56

+0

也許你可以將答案標記爲接受。 – imaginaryboy 2010-11-08 17:15:26

+0

(也是堆棧溢出的新手,現在回答我以前的問題和解答 - 對不起) – rpheath 2010-11-10 13:53:51

相關問題