我一直在学习iDev,但我还是无法处理http请求。 这似乎很疯狂,但我谈论同步请求的每个人都不理解我。好吧,尽可能保持后台队列以提供流畅的UI非常重要。但在我的情况下,我从服务器加载JSON数据,我需要立即使用这些数据。 我实现它的唯一方法是信号量。好吗?或者我必须使用其他?我尝试了NSOperation,但事实上我需要很多小的请求所以为我创建每个类似乎不是简单的阅读代码。
func getUserInfo(userID: Int) -> User {
var user = User()
let linkURL = URL(string: "https://server.com")!
let session = URLSession.shared
let semaphore = DispatchSemaphore(value: 0)
let dataRequest = session.dataTask(with: linkURL) { (data, response, error) in
let json = JSON(data: data!)
user.userName = json["first_name"].stringValue
user.userSurname = json["last_name"].stringValue
semaphore.signal()
}
dataRequest.resume()
semaphore.wait(timeout: DispatchTime.distantFuture)
return user
}
答案 0 :(得分:1)
您写道,人们不了解您,但另一方面,它表明您不了解异步网络请求的工作原理。
例如,假设您在特定时间设置闹钟。
现在您有两种选择可以花费以下时间。
就编程语言而言,您需要一个完成处理程序,在加载数据时由网络请求调用。在Swift中,你正在使用一个闭包。
为方便起见,声明一个带有success
和failure
个案例的关联值的枚举,并将其用作完成处理程序中的返回值
enum RequestResult {
case Success(User), Failure(Error)
}
为您的函数添加一个完成处理程序,包括错误情况。 强烈建议始终处理异步任务的错误参数。当数据任务返回时,调用完成闭包,根据情况通过user
或error
func getUserInfo(userID: Int, completion:@escaping (RequestResult) -> ()) {
let linkURL = URL(string: "https://server.com")!
let session = URLSession.shared
let dataRequest = session.dataTask(with: linkURL) { (data, response, error) in
if error != nil {
completion(.Failure(error!))
} else {
let json = JSON(data: data!)
var user = User()
user.userName = json["first_name"].stringValue
user.userSurname = json["last_name"].stringValue
completion(.Success(user))
}
}
dataRequest.resume()
}
现在您可以使用以下代码调用该函数:
getUserInfo(userID: 12) { result in
switch result {
case .Success(let user) :
print(user)
// do something with the user
case .Failure(let error) :
print(error)
// handle the error
}
}
在实践中,完成版块中semaphore
和switch result
行之后的时间点完全相同。
永远不要使用信号量作为不在处理异步模式的不在场证明
我希望闹钟示例阐明异步数据处理的工作原理以及为什么获得通知(主动)而非等待(被动)的效率要高得多。
答案 1 :(得分:-1)
请勿尝试强制网络连接同步工作。它总会导致问题。无论什么代码进行上述调用都可能被阻止长达90秒(30秒DNS超时+ 60秒请求超时),等待该请求完成或失败。那是永恒的。如果该代码在iOS上的主线程上运行,操作系统将在您达到90秒标记之前很久就终止您的应用程序。
相反,设计代码以异步处理响应。基本上是:
对于一个非常简单的示例,如果您有一个方法可以使用登录用户的名称更新UI,而不是:
[self updateUIWithUserInfo:[self getUserInfoForUser:user]];
你会将其重新设计为:
[self getUserInfoFromServerAndRun:^(NSDictionary *userInfo) {
[self updateUIWithUserInfo:userInfo];
}];
这样当对请求的响应到达时,它会执行UI更新操作,而不是尝试启动UI更新操作并阻止它等待来自服务器的数据。
如果您需要两件事 - 比如userInfo和用户已阅读的书籍列表,您可以这样做:
[self getUserInfoFromServerAndRun:^(NSDictionary *userInfo) {
self.userInfo = userInfo;
[self updateUI];
}];
[self getBookListFromServerAndRun:^(NSDictionary *bookList) {
self.bookList = bookList;
[self updateUI];
}];
...
(void)updateUI
{
if (!self.bookList) return;
if (!self.userInfo) return;
...
}
或其他什么。街区是你的朋友。 : - )
是的,重新考虑您的代码以异步方式工作是一件痛苦的事情,但最终结果更加可靠,并且可以带来更好的用户体验。