我想以某种方式异步验证 ABPadLockScreen 中的引脚,因为引脚未保存在设备上。我将 Alamofire 与 PromiseKit 一起用于 http 请求以实现 promise 。
我曾尝试使用 AwaitKit
但问题是我陷入了僵局。
我也尝试过使用semaphore
,但结果是一样的。由于我无法更改 ABPadLock 方法来适应完成处理程序之类的东西,我需要一些解决方案,它是否阻塞主线程并不重要,只要它能工作即可。
Alamofire request method:
public func loginAsync(pinCode: String?, apiPath: String?) -> Promise<LoginResult>{
return Promise { fullfil, reject in
let params = [
"Pin": pinCode!
]
Alamofire.request(.POST, "\(baseUrl!)/\(apiPath!)", parameters: params).responseObject{(response: Response<LoginResult, NSError>) in
let serverResponse = response.response
if serverResponse!.statusCode != 200 {
reject(NSError(domain: "http", code: serverResponse!.statusCode, userInfo: nil))
}
if let loginResult = response.result.value {
fullfil(loginResult)
}
}
}
}
ABPadLockScreen pin validation method:
public func padLockScreenViewController(padLockScreenViewController: ABPadLockScreenViewController!, validatePin pin: String!) -> Bool {
let pinCode = pin!
let defaults = NSUserDefaults.standardUserDefaults()
let serverUrl = defaults.stringForKey(Util.serverUrlKey)
let service = AirpharmService(baseUrl: serverUrl)
service.loginAsync(pinCode, apiPath: "sw/airpharm/login").then { loginResult -> Void in
if loginResult.code == HTTPStatusCode.OK {
AirpharmService.id = loginResult.result!.id
}
}
return false // how do i get the result of above async method here?
}
With semaphore:
public func padLockScreenViewController(padLockScreenViewController: ABPadLockScreenViewController!, validatePin pin: String!) -> Bool {
var loginResult: LoginResult?
let defaults = NSUserDefaults.standardUserDefaults()
let baseUrl = defaults.stringForKey(Util.serverUrlKey)
let service = AirpharmService(baseUrl: baseUrl)
let semaphore: dispatch_semaphore_t = dispatch_semaphore_create(0)
service.loginAsync(pin, apiPath: "sw/airpharm/login").then { loginResultRaw -> Void in
loginResult = loginResultRaw
dispatch_semaphore_signal(semaphore)//after a suggestion from Josip B.
}
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
return loginResult != nil // rudimentary check for now
}
编辑:
After a suggestion from Josip B. i added semaphore signal in then, but it still doesn't work
AirpharmService
是一个包含名为 id 的静态属性和 Alamofire
请求方法的类。
ABPadLockScreen
pin 验证在 ViewController
的主线程上完成
已解决的编辑:
感谢大家对我以及我对 swift 和 iOS 不太了解的知识如此耐心。这里有很多好的答案,在我看来,最后我只是选择了最简单的解决方案。我听了Losiowaty -建议;当我从服务器收到响应时,实现了一个微调器并手动关闭了锁定屏幕。我用过 SwiftSpinner .最终的解决方案如下所示:
public func padLockScreenViewController(padLockScreenViewController: ABPadLockScreenViewController!, validatePin pin: String!) -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
let baseUrl = defaults.stringForKey(Util.serverUrlKey)
let service = AirpharmService(baseUrl: baseUrl)
SwiftSpinner.show("Logging in. Please wait...")
service.loginAsync(pin, apiPath: "sw/airpharm/login").then { loginResult -> Void in
if loginResult.code == HTTPStatusCode.OK {
SwiftSpinner.hide()
AirpharmService.id = loginResult.result!.id
self.unlockWasSuccessfulForPadLockScreenViewController(padLockScreenViewController)
} else if loginResult.code == HTTPStatusCode.Unauthorized {
let toast = JLToast.makeText("Invalid pin, please try again", duration: 5)
toast.show()
SwiftSpinner.hide()
} else {
let toast = JLToast.makeText("\(loginResult.code) sent from server. Please try again.", duration: 5)
toast.show()
SwiftSpinner.hide()
}
}.error { error in
let toast = JLToast.makeText("\((error as NSError).code) sent from server. Please try again.", duration: 5)
toast.show()
SwiftSpinner.hide()
}
return false
}
最佳答案
很高兴很多人试图帮助您使异步调用同步。我个人同意@OOPer 和他的意见,即您应该重新设计您的代码,尤其是在查看了 ABPadLockScreen
代码之后。他们似乎不支持异步 pin 验证,这是一种耻辱。此外,从他们的 github 存储库看来,原作者至少暂时放弃了该项目。
我会尝试这样解决您的问题:
public func padLockScreenViewController(padLockScreenViewController: ABPadLockScreenViewController!, validatePin pin: String!) -> Bool {
let pinCode = pin!
let defaults = NSUserDefaults.standardUserDefaults()
let serverUrl = defaults.stringForKey(Util.serverUrlKey)
let service = AirpharmService(baseUrl: serverUrl)
service.loginAsync(pinCode, apiPath: "sw/airpharm/login").then { loginResult -> Void in
if loginResult.code == HTTPStatusCode.OK {
AirpharmService.id = loginResult.result!.id
self.handleLoginOk()
} else {
self.handleLoginFailed()
}
}
// disable interaction on padlock screen
// indicate to user that an async operation is going on, show a spinner
return false // always return false here
}
func handleLoginOk() {
// dismiss the ABPadlockScreenViewController manually
}
func handleLoginFailed() {
// dismiss the spinner indicating the async operation
// restore user interaction to padlock screen
}
通过这种方法,您的用户将知道正在发生某些事情(微调器,您可以使用例如 SVProgressHUD
作为嵌入式解决方案)并且应用程序没有挂起。这在用户体验方面非常重要,因为连接不畅的用户可能会因为认为应用挂起并关闭它而感到沮丧。
但是有一个潜在的问题 - 如果当您从委托(delegate)方法返回 false
时挂锁屏幕显示某种“错误的 pin”消息,则用户可能会看到它,从而造成一些困惑。现在可以通过制作/定位微调器来解决这个问题,使其模糊消息,尽管这是一个非常粗糙和不优雅的解决方案。另一方面,也许可以对其进行足够的自定义,以便不显示任何消息,并且您会在服务器端验证后显示自己的警报。
让我知道您对此有何看法!
关于ios - 等待异步请求结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38684648/