最新消息:20190529 VPS服务器已从腾讯云香港换为Vultr新加坡,主题仍用朋友推荐的大前端D8

[已解决]swift中Alamofire的request的responseJSON不执行不返回了

iOS crifan 911浏览 0评论

代码:

func getRequestRespJson(httpRequest:Alamofire.Request, mergedAllPara:Dictionary<String, AnyObject>, respJsonHandler: (Alamofire.Result<JSON, NSError>, mergedAllPara:Dictionary<String, AnyObject>) -> Void) {
    gLog.info("httpRequest=\(httpRequest), mergedAllPara=\(mergedAllPara), respJsonHandler=\(respJsonHandler)")
    dispatchBackground_async({
        httpRequest.responseJSON(completionHandler: { response in
            gLog.debug("request=\(response.request), response=\(response.response), statusCode=\(response.response?.statusCode), result=\(response.result)")

但是对于此处的:

responseJSON的completionHandler

始终无法进入了

注:

之前没有使用dispatch_semaphore_t时,代码是可以正常工作的

dispatch_semaphore_t

此处使用了:

对应代码是:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        self.window?.rootViewController = SingletonRootNC()
        if SingletonLoginRegisterVC().tryRestoreUserAndPassword() {
            SingletonLoginRegisterVC().isLogin = true
            SingletonLoginRegisterVC().isRegister = false
            SingletonLoginRegisterVC().loginAction()
            dispatch_semaphore_wait(loginDoneSemaphore, DISPATCH_TIME_FOREVER)
}
var loginDoneSemaphore:dispatch_semaphore_t!
func resetGlobalValues(){
    gLog.debug("")
    loginDoneSemaphore = dispatch_semaphore_create(0)
}

导致:Alamofire的responseJSON不返回了。。。

搜:

swift dispatch_semaphore_t alamofire

使用 Alamofire 执行同步请求 – Hran’s

好像是:

Alamofire内部 也是用到了dispatch_semaphore_t?

线程锁 —- NSLock , @synchronized 和 dispatch_semaphore_t – IOS888888的专栏 – 博客频道 – CSDN.NET

Alamofire-Synchronous/Alamofire+Synchronous.swift at master · Dalodd/Alamofire-Synchronous

ios – Capturing data from Alamofire – Stack Overflow

然后,如果去掉了:

dispatch_semaphore_t

则:Alamofire就正常工作,可以正常返回值了。

 alamofire not response dispatch_semaphore_t

 alamofire not response   semaphore

alamofire no response semaphore

alamofire  semaphore

Check if all concurrent requests have been completed · Issue #224 · Alamofire/Alamofire

好像也遇到,可能算是类似的问题了

然后去改为:

确保所有的调用到Alamofire的地方,都是主线程,

结果也还是不行。

Allow synchronous calls · Issue #1147 · Alamofire/Alamofire

iOS Free App: How to return value from Alamofire

tvOS: Dynamic TopShelf Based on Remote JSON – HalGatewood.com

->好像responseJSON没有和dispatch_semaphore_create冲突啊?

alamofire DISPATCH_TIME_FOREVER

突然想到了:

貌似是:

Alamofire自己内部变态:

每次返回的http的response时,都是故意,主动的,返回到主线程中:

导致:

此处的:

            dispatch_semaphore_wait(loginDoneSemaphore, DISPATCH_TIME_FOREVER)

是在主线程(的didFinishLaunchingWithOptions)中的

-》因此导致了让主线程永远等待loginDoneSemaphore

-》而Alamofire返回的内容,默认是返回到主线程中的(而不是你调用时候的线程)

-》从而导致死锁了:

Alamofire的responseJSON,想要获得主线程,才能返回JSON内容

而此时,主线程已经被我们的loginDoneSemaphore锁住了,永远在等待DISPATCH_TIME_FOREVER了。

-》解决办法,尝试去看看,Alamofire中,是否有配置选项,使得可以设置response的内容,不返回到主线程

通过看Alamofire的接口定义:

extension Request {
    /**
            Creates a response serializer that returns a JSON object constructed from the response data using 
            `NSJSONSerialization` with the specified reading options.
            – parameter options: The JSON serialization reading options. `.AllowFragments` by default.
            – returns: A JSON object response serializer.
        */
    public class func JSONResponseSerializer(options options: NSJSONReadingOptions = default) -> Alamofire.ResponseSerializer<AnyObject, NSError>
    /**
            Adds a handler to be called once the request has finished.
            – parameter options:           The JSON serialization reading options. `.AllowFragments` by default.
            – parameter completionHandler: A closure to be executed once the request has finished.
            – returns: The request.
        */
    public func responseJSON(queue queue: dispatch_queue_t? = default, options: NSJSONReadingOptions = default, completionHandler: Alamofire.Response<AnyObject, NSError> -> Void) -> Self
}

默认是返回到queue是default

-》此处暂时没源码,所以看不到是哪个线程

但是能猜测出来是主线程

-》通过设置对应的queue,也许问题能够解决。

果然是这个原因,去改为:

let BackgroundThread:dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)
    dispatchBackground_async({
        httpRequest.responseJSON(queue: BackgroundThread, completionHandler: { response in
            gLog.debug("request=\(response.request), response=\(response.response), statusCode=\(response.response?.statusCode), result=\(response.result)")
}

即可正常执行。

-》这也间接的解决了,之前一直困扰我的问题:

为何Alamofire的所有的response,默认都返回到dispatch_get_main_queue的主线程中呢?

原来是:

Alamofire的所有的response函数,默认如果不传入对应的queue,则默认,应该就是main queue。

去下载源码,再去确认此推断:

然后才看懂:

default是nil,最终返回时,如果发现queue是(default的)nil,则使用主线程:

    public func responseJSON(
        queue queue: dispatch_queue_t? = nil,
        options: NSJSONReadingOptions = .AllowFragments,
        completionHandler: Response<AnyObject, NSError> -> Void)
        -> Self
    {
        return response(
            queue: queue,
            responseSerializer: Request.JSONResponseSerializer(options: options),
            completionHandler: completionHandler
        )
    }
}
-》
    public func response<T: ResponseSerializerType>(
        queue queue: dispatch_queue_t? = nil,
        responseSerializer: T,
        completionHandler: Response<T.SerializedObject, T.ErrorObject> -> Void)
        -> Self
    {
            dispatch_async(queue ?? dispatch_get_main_queue()) { completionHandler(response) }

至此,算是完全搞懂了。。。

另外:

然后也才注意到:

Check if all concurrent requests have been completed · Issue #224 · Alamofire/Alamofire

中的回复:

This is because responseSwiftyJSON was dispatched to main queue, do this and your problem is solved.
return response(queue: dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0),responseSerializer: User.userResponseSerializer,
completionHandler: completionHandler)

其实就已经说明问题,并给出解决办法了。。。

所以,最后,相关部分的代码是:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        self.window?.rootViewController = SingletonRootNC()
        if SingletonLoginRegisterVC().tryRestoreUserAndPassword() {
            SingletonLoginRegisterVC().isLogin = true
            SingletonLoginRegisterVC().isRegister = false
            SingletonLoginRegisterVC().loginAction()
            dispatch_semaphore_wait(loginDoneSemaphore, DISPATCH_TIME_FOREVER)
            gLog.debug("has dispatched loginDoneSemaphore")
            if gCurUserItem.hasLogined {
                gLog.info("login successfully")
    }
}
func getRequestRespJson(httpRequest:Alamofire.Request, mergedAllPara:Dictionary<String, AnyObject>, respJsonHandler: (Alamofire.Result<JSON, NSError>, mergedAllPara:Dictionary<String, AnyObject>) -> Void) {
    gLog.info("httpRequest=\(httpRequest), mergedAllPara=\(mergedAllPara), respJsonHandler=\(respJsonHandler)")
    dispatchBackground_async({
        httpRequest.responseJSON(queue: BackgroundThread, completionHandler: { response in
            gLog.debug("request=\(response.request), response=\(response.response), statusCode=\(response.response?.statusCode), result=\(response.result)")
    }
}

即可避免由于:

dispatch_semaphore_wait(loginDoneSemaphore, DISPATCH_TIME_FOREVER)

而导致的死锁的问题,使的Alamofire的responseJSON可以正常返回数据了。

转载请注明:在路上 » [已解决]swift中Alamofire的request的responseJSON不执行不返回了

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
69 queries in 0.103 seconds, using 18.79MB memory