我有一个get xml类并解析它。
+ (instancetype)sharedRssNewsLoader
{
static BGMRssNewsLoader *sharedRssNewsLoader = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedRssNewsLoader = [[self alloc] initPrivate];
});
return sharedRssNewsLoader;
}
- (instancetype)initPrivate
{
self = [super init];
//did the superclass's designated initializer succeed?
if (self)
{
self.rssNewsItems = [[NSMutableArray alloc] init];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config
delegate:nil
delegateQueue:nil];
//RSS call
[self fetchFeed];
}
return self;
}
- (void)fetchFeed
{
NSString *requestString = @"http://xxx...";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
self.rssXmlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
DDLogVerbose(@"rssXmlString: %@", self.rssXmlString);
dispatch_sync(dispatch_get_main_queue(), ^{
[self parseXML:self.rssXmlString];
});}
];
[dataTask resume];
}
//parse XML
- (void)parseXML:(NSString *)source
{
NSError *error = nil;
DDXMLDocument *theDocument = [[DDXMLDocument alloc] initWithXMLString:source
options:0
error:&error];
NSArray *xmlItems = [theDocument nodesForXPath:@"//item"
error:&error];
for(DDXMLElement *itemElement in xmlItems)
{
NSString *itemTitleValue = [[[itemElement elementsForName:@"title"] lastObject] stringValue];
NSString *itemDescriptionValue = [[[itemElement elementsForName:@"title"] lastObject] stringValue];
BGMRssNewsEntry *rssEntry = [[BGMRssNewsEntry alloc] initRssNewsEntryWithTitle:itemTitleValue
rssText:itemDescriptionValue
rssUrl:nil
rssDate:nil
isRssRead:NO];
[self.rssNewsItems addObject:rssEntry];
}
}
//if a programmer calls [[BGMItemsStore alloc] init], let him know the error of his ways
- (instancetype) init
{
@throw [NSException exceptionWithName:@"Singleton"
reason:@"You are wrong! Use +[BBGMRssNewsLoader sharedRssNewsLoader]"
userInfo:nil];
return nil;
}
我想在表格中显示结果。所以在我做的其他课程中:
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
//custom initialization
//initialization sharedRssNewsLoader with rssItems array and RSS call
[BGMRssNewsLoader sharedRssNewsLoader];
}
return self;
}
但我的表格绝对清楚。我知道当我使用NSURLSessionDataTask
时我需要切换到main_queue,我做到了。我认为我搞乱线程:(
答案 0 :(得分:0)
BGMRssNewsLoader
异步加载数据,parseXML
正在向self.rssNewsItems
对象添加条目。但是,当这个异步请求完成时,我不知道它告诉表重新加载自己的位置。如果表视图的数据源尝试立即检索rssNewsItems
数组,则在异步请求完成之前它可能为空。
通常,当您完成加载数据时,您需要调用[self.tableView reloadData]
(通过在BGMRssNewsLoader
实例化期间提供tableview作为参数,或者通过它会发布表视图控制器正在观察的通知,或者提供一个完成块参数,您可以在其中执行reloadData
)。
我还建议临时添加一个断点或日志语句,将对象添加到rssNewsItems
数组,以确保成功检索和解析XML提要。
例如,我可能会退出fetch
并定义一个类似的方法:
- (void)fetchFeedWithCompletionBlock:(void (^)(NSArray *items, NSError *error))completion
{
NSString *requestString = @"http://xxx...";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
self.rssXmlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
DDLogVerbose(@"rssXmlString: %@", self.rssXmlString);
dispatch_sync(dispatch_get_main_queue(), ^{
[self parseXML:self.rssXmlString];
if (completion) {
completion(self.rssNewsItems, nil);
}
});
}];
[dataTask resume];
}
顺便说一下,我不会initPrivate
方法启动fetch
。您希望调用者能够提供它想要的任何完成块。
然后让tableview的控制器做类似的事情:
[[BGMRssNewsLoader sharedRssNewsLoader] fetchFeedWithCompletionBlock:^(NSArray *items, NSError *error) {
// use the items array and/or error
[self.tableView reloadData];
}];
显然,fetchFeedWithCompletionBlock
实际上应该检测到错误并使用适当的NSError
调用完成块(因此表视图可以决定它是如何呈现错误的...单例不应该&#39}对于UI本身做任何事情),但希望这说明了一个网络对象的想法,它提供了一个完成块,允许调用者在异步请求完成时指定它想要做什么。