Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Networking with Alamofire on WatchOS

I am building an app extension for WatchOS and I want to do some URL requests in the Watch app. I am using Alamofire for the networking part.

Whenever I do a simple request, I am getting these errors in both the simulator as well as on the real device: load failed with error Error Domain=NSURLErrorDomain Code=-2000 "can’t load from network"

It's unclear to me why this happens. The watch is paired with the phone. Using Charles Proxy I can see that the requests were not sent over the network, so it fails before even sending it.

Any ideas are welcome.

EDIT Here is a working extraction of my Communications class:

import Foundation
import Alamofire

class Communication {
    internal lazy var manager = Communication.getSessionManager()

    typealias SuccesBlock = (DataResponse<Any>?) -> ()
    typealias FailureBlock = (DataResponse<Any>?, Error) -> ()
    typealias ProgressBlock = (Progress) -> ()

    internal static var serverTrustPolicyManager: ServerTrustPolicyManager {
        get {
            return ServerTrustPolicyManager(policies: [:])
        }
    }

    static func getSessionManager(_ serializeRequest:Bool = false) -> Alamofire.SessionManager {
        let manager = Alamofire.SessionManager(configuration: URLSessionConfiguration.default, delegate: Alamofire.SessionManager.default.delegate, serverTrustPolicyManager: serverTrustPolicyManager)
        return manager
    }

    static var httpHeaders: HTTPHeaders {
        get {
            var httpHeaders = HTTPHeaders()
            httpHeaders["Accept"] = "application/json"
            return httpHeaders
        }
    }

    func get(_ url: URL, parameters: [String: Any]?, success: @escaping SuccesBlock, failure: @escaping FailureBlock) {
        manager.request(url, method: HTTPMethod.get, parameters: parameters, encoding: URLEncoding.default, headers: Communication.httpHeaders).validate().responseJSON { [weak self] (response) in
            self?.handle(response, success: success, failure: failure)
        }
    }

    internal func handle(_ response: DataResponse<Any>, success: @escaping SuccesBlock, failure: @escaping FailureBlock) {
        switch response.result {
        case .success:
            DispatchQueue.main.async {
                success(response)
            }
        case .failure(let error):
            DispatchQueue.main.async {
                failure(response, error)
            }
        }
    }
}

Anything I send to the get(_ url: URL, parameters: [String: Any]?, success: @escaping SuccesBlock, failure: @escaping FailureBlock) function is giving the -2000 error. The .responseJSON code block is never executed.

EDIT 2

The complete error I am getting is the following:

`2018-09-20 12:12:48.006544+0100 My App Watch Extension[61347:2465172] Task <F80A9AD4-519B-424C-868A-8E239C949016>.<7> load failed with error Error Domain=NSURLErrorDomain Code=-2000 "can’t load from network" UserInfo={NSLocalizedDescription=can’t load from network, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <F80A9AD4-519B-424C-868A-8E239C949016>.<7>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <F80A9AD4-519B-424C-868A-8E239C949016>.<7>"
), NSErrorFailingURLStringKey=https://my.request.url, _kCFNetworkErrorConditionalRequestKey=<CFMutableURLRequest 0x78f37a70 [0x201628c]> {url = https://my.request.url, cs = 0x0}, _kCFNetworkErrorCachedResponseKey=<CFCachedURLResponse 0x7b3d7f20 [0x201628c]>, NSUnderlyingError=0x7b436380 {Error Domain=kCFErrorDomainCFNetwork Code=-2000 "(null)" UserInfo={_kCFNetworkErrorCachedResponseKey=<CFCachedURLResponse 0x7b3d7f20 [0x201628c]>, _kCFNetworkErrorConditionalRequestKey=<CFMutableURLRequest 0x78f37a70 [0x201628c]> {url = https://my.request.url, cs = 0x0}}}, NSErrorFailingURLKey=https://my.request.url} [-2000]`

After getting this error in the console I can now see the request is still sent and succeeds. I assumed this wasn't the case after seeing this error, but I now see that after some delay the request works as expected.

So in the end the app will work, however, the question that remains is: Why do I get this error and how can I get rid of it?

like image 817
Bocaxica Avatar asked Sep 19 '18 11:09

Bocaxica


People also ask

What is Alamofire in iOS?

Alamofire is an HTTP network-based library which is used to handle the web request and response in iOS and MacOS. It is the wrapper class of URLSession and provides an interface on the top of Apple's networking stack.

Does Alamofire use URLSession?

Alamofire is built on top of NSURLSession, and is less lines of code to do REST interactions with (POST/GET/PUT/etc). It will get you "90%" of the way, but if you need to do super specialized network calls, you will need to use NSURLSession.

Can I use Alamofire in SwiftUI?

Adding Alamofire Into Our Project Launch a new Xcode, SwiftUI based project and add the Alamofire dependency. You can use Cocoapods, Swift Package Manager or Carthage, whichever works the best for you. Once that's done, simply import Alamofire into your Swift class.

Is Alamofire a framework?

And that's it! The Alamofire. framework is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.


1 Answers

The error description is

NSURLErrorCannotLoadFromNetwork

This error is sent when the task needs to load from the network, but is blocked from doing so by the “load only from cache” directive.

You can solve it by setting the requestCachePolicy of the Alamofire request, like this i.e.:

class RequestManager {

    let manager: SessionManager = {
        let configuration = URLSessionConfiguration.default
        configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
        return SessionManager(configuration: configuration)
    }()

    func fetch() {

       manager.request("https://www.bla.blub") 

       ...
like image 56
chris Avatar answered Sep 21 '22 07:09

chris