我已经创建了类StartConnection来处理我的NSURL请求。它从我的AppDelegate调用两次,效果很好。它也被另一个类调用,并且也很有效。这是StartConnection的实现:
#import "StartConnection.h"
#import "BlaBlaBlog-swift.h"
@implementation StartConnection
{
BOOL startedForBlog;
}
- (void)getRssFileWithUrl: (NSString*)rssUrlString forBlog:(BOOL)forBlog
{
startedForBlog = forBlog;
NSURL *url = [NSURL URLWithString:rssUrlString];
NSURLRequest *rssRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:rssRequest delegate:self];
[connection start];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
dataSize = [response expectedContentLength];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (receivedData==nil )
{
receivedData = [[NSMutableData alloc]init];
}
// Append the new data to the instance variable you declared
[receivedData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
self.receivedDataComplete = receivedData;
if (startedForBlog){
[self.delegate performSelector: @selector(receiveDataCompleted)];
}
else
[self.delegate performSelector: @selector(receivePodCastDataCompleted)];
}
为了获得SWIFT的经验,我在我的代码中添加了一个实验SWIFT类,它也使用了StartConnection.h。在调试器中,我可以看到正在创建一个StartConnection实例,并且getFileWithUrl方法似乎正常被踢掉了。但就是这一切。没有调用任何委托方法。
这是SWIFT课程:
import UIKit
class CheckActuality: NSObject, GetReceivedDataProtocol, WordPressParserDelegate {
var retrievePostData = StartConnection()
var parseCompleted: Bool=false
var result: Bool = true
lazy var wpParser = WordPressParser()
lazy var defaults = NSUserDefaults.standardUserDefaults()
func isActual () -> Bool {
var url = "http://blablablog.nl/new_api.php?function=get_recent_posts&count=1"
self.retrievePostData.delegate=self
self.retrievePostData.getRssFileWithUrl(url, forBlog:true)
while !self.parseCompleted
{
// wait till wpparser has completed
}
if self.wpParser.arrayWithPostDictionaries.count == 1
// Some info has been retrieved
{
var posts: NSArray = wpParser.arrayWithPostDictionaries
var post: NSDictionary = posts.objectAtIndex(0) as NSDictionary
var latestPostUrl: String = post.objectForKey("postUrl") as String
var currentLatestPostUrl = defaults.stringForKey("ttt")
if latestPostUrl != currentLatestPostUrl {
result = false
}
else {
result = true
}
}
return result
}
func receiveDataCompleted () {
if self.retrievePostData.receivedDataComplete != nil
{
self.wpParser.delegate=self
self.wpParser.parseData(retrievePostData.receivedDataComplete)
}
else
{
// warning no internet
}
}
func wpParseCompleted () {
self.parseCompleted=true
}
}
要完成,我的AppDelegate中的调用如下所示:
//
// retrieving PostData. Create a connection, set delegate to self en start with created url
//
retrievePostData = [[StartConnection alloc]init];
retrievePostData.delegate = self;
NSString *url = [[wordPressUrl stringByAppendingString:apiString] stringByAppendingString:pageCountString];
[retrievePostData getRssFileWithUrl:url forBlog:(BOOL)true];
//
// retrieving PodcastData. Create a connection, set delegate to self en start with created url
//
retrievePodCastData = [[StartConnection alloc]init];
retrievePodCastData.delegate = self;
[retrievePodCastData getRssFileWithUrl:podcastUrl forBlog:(BOOL)false];
我几乎一天都不知所措。希望你们中的一些经验丰富的人可以帮助这个初学者。
答案 0 :(得分:1)
while !parseCompleted
循环阻塞主线程,直到下载和解析完成。但是接收数据的处理也发生在主线程上,所以如果该线程被阻止,你的应用就会陷入僵局。
我会消除while
循环并将所有后期处理放在receivedDataComplete
方法中。
顺便说一句,这种变化隐含的事实是isActual
必须是异步方法。因此,不应返回Bool
值,而应该是Void
返回类型,但您应该使用completionHandler
模式(并且我将其更改为也返回错误对象,也是):
class CheckActuality: NSObject, GetReceivedDataProtocol, WordPressParserDelegate {
let errorDomain = "com.domain.app.CheckActuality"
lazy var retrievePostData = StartConnection()
lazy var wpParser = WordPressParser()
lazy var defaults = NSUserDefaults.standardUserDefaults()
var completionHandler: ((latestPost: Bool!, error: NSError?)->())!
func isActual(completionHandler: (latestPost: Bool!, error: NSError?)->()) {
// save the completionHandler, which will be called by `receiveDataCompleted` or `wpParseCompleted`
self.completionHandler = completionHandler
// now perform query
let url = "http://blablablog.nl/new_api.php?function=get_recent_posts&count=1" // as an aside, use `let` here
retrievePostData.delegate = self // also note that use of `self` is redundant here
retrievePostData.getRssFileWithUrl(url, forBlog:true)
}
func receiveDataCompleted () {
if retrievePostData.receivedDataComplete != nil {
wpParser.delegate = self
wpParser.parseData(retrievePostData.receivedDataComplete)
} else {
// frankly, I'd rather see you change this `receiveDataCompleted` return the `NSError` from the connection, but in the absence of that, let's send our own error
let error = NSError(domain: errorDomain, code: 1, userInfo: nil)
completionHandler(latestPost: nil, error: error)
}
}
func wpParseCompleted () {
if wpParser.arrayWithPostDictionaries.count == 1 { // Some info has been retrieved
let posts: NSArray = wpParser.arrayWithPostDictionaries
let post: NSDictionary = posts.objectAtIndex(0) as NSDictionary
let latestPost: String = post.objectForKey("postUrl") as String
let currentlatestPost = defaults.stringForKey("ttt")
completionHandler(latestPost: (latestPost != currentlatestPost), error: nil)
}
// again, I'd rather see you return a meaningful error returned by the WordPressParser, but I'll make up an error object for now
let error = NSError(domain: errorDomain, code: 2, userInfo: nil)
completionHandler(latestPost: nil, error: error)
}
}
现在,我不知道latestPost
是否是您尝试返回的值的合适名称,因此将其更改为对您的例程有意义的任何内容。此外,名称isActual
并不真正有意义,但我会让您将其更改为您想要的任何内容。
无论如何,当您使用它时,您将使用尾随闭包语法来指定将异步执行的completionHandler
块:
let checkActuality = CheckActuality()
func someFunc() {
checkActuality.isActual() { latestPost, error in
if error != nil {
// do whatever error handling you want
println(error)
} else if latestPost {
// yes, latest post
} else {
// nope
}
}
// note, do not try to check `latestPost` here because the
// above closure runs asynchronously
}
毋庸置疑,这是completionHandler
模式,但在查看代码时,您似乎更喜欢delegate
模式。如果您想使用delegate
模式实现此功能,则可以。但是这个想法是一样的:这个isActual
方法(无论你最终将它重命名为)都是异步运行的,所以你必须在调用者完成时通知它。