Setting timeoutInterval on Alamofire DataRequest - swift

I'm making a custom class that takes an Alamofire DataRequest in it's initializer. Now I want to add a timeoutInterval to it, but I'm getting the compiling error
Value of type 'DataRequest' has no member 'timeoutInterval'
Here is the code:
init(request: DataRequest, timeoutInterval: Double = 10) {
request.timeoutInterval = timeoutInterval // <- compile error here
self.request = request
}
Obviously Alamofire DataRequest doesn't have that property. But is there any other way to specify the timeout to a request in this way (without using a SessionManager preferable)? URLRequest has it, so it should be possible somehow, but I cannot figure out how.
I know that this question has been asked before here on Stack Overflow, but I cannot find any answer that fits this situation.

In Alamofire 5.1 we've added a requestModifier parameter to the top level request methods that gives you access to the URLRequest that will be performed.
In Alamofire 4 you have a few, less elegant options. One straightforward way to set it is to use a RequestAdapter that will set it as part of the request pipeline. Another, more involved option, is to move from the top level request method that takes individual parameters, such as headers, to the API that takes a URLRequestConvertible value. That way you have full control over the URLRequests that are performed by Alamofire on your behalf.

Related

CoreData - Fetch NSManagedObject with perform and background thread

I'm developing an SDK that uses only 1 NSManagedObjectContext with type of privateQueueConcurrencyType.
In order to fetch objects, i'm using perform() and then i pass the results to a closure.
I'm calling this method from a background thread and also use the result on a background thread (which might be different than the one that called it).
I know that passing objects between threads is a no-go, but i'm not satisfied with the way i handle it today.
The way I handle it, is that every NSManagedObject is mapped to "normal" Swift object and then i use the swift object.
For example:
Foreach NSManagedObject from the results, i create new Object (which is not NSManagedObject) and then i use these objects.
I would like to use the NSManagedObjects instead of creating new ones that holds similar data.
What's the best approach to do it?
Can I still use the NSManagedObject?
func getRecordsByPredicate<T: NSManagedObject>(type: T.Type, predicate: NSPredicate, success: #escaping (_ record: [T]?) -> Void, failure: #escaping () -> Void) {
self.context.perform {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: type.self))
fetchRequest.includesPropertyValues = false
fetchRequest.predicate = predicate
do {
let results = try context.fetch(fetchRequest)
success(results as? [T])
} catch {
print(error.localizedDescription)
failure()
}
}
}
Providing an API with CoreData involved is difficult, at best.
You can not expose only the managed object in the API, since these are tied to a specific thread or dispatch queue which is private to your library. You would require the client to pass a Managed Object Context as well which defines the execution context where the client will use the managed object.
If your internal MOC and the client's MOC is not the same, the API inevitably becomes asynchronous - or it will block a thread.
You may require that this API can be used on the main thread only and your library takes care to use the same MOC as well. This of course has a couple of drawbacks, possibly making the API asynchronous would be only one of it.
Since you also cannot force to make the developer read your documentation, the first developer using your API will likely not call it from the main thread. ;)
Another alternative would be to let the client pass a closure to the API instead, which is then called from your library on the right execution context. This also makes the API asynchronous, and also requires the developer a deep understanding of CoreData as well, since she gets CoreData managed objects.
Your first approach using "Swift" values is probably the best approach to handle this. Make CoreData an "implementation detail" of your library and save the developers the hassles involved when using CoreData.

A solution to track a batch of HTTP requests in swift 3.0

I am using swift 3.0 running under iOS 10.0 and I want to craft some code that fires when a batch condition is met.
for i in 0 ..< rex {
async code, disappears and does it stuff
}
Imagine the async code is a collection of URL requests, that basically background as soon as I loop thru them. Now how can I fire off more code when "rex" requests have completed?
I thought of setting up a timer to watch and check every second, but its surely not a good solution.
I thought kicking off another thread to simply watch the data being collected, and fire when its quota is full, but well that's worse then the timer really.
I am thinking to include a test at the end of each URL request to see if it was the last that completed and than uses the NotificationCenter, but is this the optimal solution?
While OperationQueue (aka NSOperationQueue) is a good choice in many cases, it's not suitable for your use case. The problem is that URL requests are called asynchronously. Your NSOperation will finish before you get a response from the webservice.
Use DispatchGroup instead
let group = DispatchGroup()
// We need to dispatch to a background queue because we have
// to wait for the response from the webservice
DispatchQueue.global(qos: .utility).async {
for i in 0 ..< rex {
group.enter() // signal that you are starting a new task
URLSession.shared.dataTask(with: urls[i]) { data, response, error in
// handle your response
// ....
group.leave() // signal that you are done with the task
}.resume()
}
group.wait() // don't ever call wait() on the main queue
// Now all requests are complete
}
So I'm pretty sure what you want can be found here. Basically you want to use GCD and have a completion closure. It's one line of code, which always makes me giggle. A longer post on the topic is here.
What you're looking for is NSOperationQueue (or OperationQueue in Swift 3). Here's a Swift tutorial (might be a bit out of date). Here's Apple's documentation on it -- in Swift 3 they drop all the NS prefixes, so it's OperationQueue / Operation.
Basically you should add each of your URL tasks as an Operation to an OperationQueue, and have a "done" Operation with each of your URL tasks as a dependency, and add it to the queue. Then as soon as all your URL tasks are done, it will call your done operation, which you can set up to do whatever you want.
You will probably need to subclass Operation so you can update the isExecuting and isFinished properties properly. This question may be of some help here.

Measuring total response time for NSURLSession's dataTaskWithRequest

When using NSURLSession's dataTaskWithRequest how can total response time be measured in the event that many NSURLSessionDataTask are created and will not necessarily be executed immediately? Storing a starting time and calculating the difference within the block doesn't account for time that a task may have been waiting for an available thread. IE:
let startTime = NSDate();
let task = session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
let responseTime = NSDate().timeIntervalSinceDate(startTime);
}
I think you can probably do this with a fairly trivial custom NSURLProtocol.
In your canInitWithRequest: method, call the setProperty:forKey:inRequest: method on NSURLProtocol to set a custom start time key for the request. Then reject the request (by returning NO) and allow the normal HTTP protocol to handle the request normally.
When you get a response, call property:forKey:inRequest: to get the start time.
With that said, there's no guarantee that the request really will start immediately after the call to canInitWithRequest:, and because there's no good way to subclass the original HTTP protocol handler class (to wrap the startLoading method), this may or may not be precise enough. I'm not sure.
So if that doesn't work, then to improve the accuracy, you would have to create a full-blown protocol that:
Returns YES in canInitWithRequest: (except if the start time has already been set for that request)
Creates a new URL session in its startLoading method (to ensure that the request will start instantly)
Adds the start time to the request
Begins the request in that new session
But even that will not necessarily give you precise timing if the request is happening while the app is in the background or if the discretionary flag is set on the session configuration. That approach also won't work very easily if you're using more than one session with different configurations. It is, however, probably the best you can do in terms of accuracy, because I doubt that there's any way to swizzle the built-in HTTP protocol class (if such a class even exists).

Will NSURLRequest timeout value overrides NSURLSessionConfiguration timeoutIntervalForRequest value?

I am creating a NSURLSession object with timeoutIntervalForRequest configuration = 120 seconds. After this I am creating a NSURLSessionDataTask object and calling the method dataTaskWithRequest:completionHandler. Here one input parameter is a NSURLRequest. Again while I create a NSURLRequest, I can specify a some of parameters like timeout, cachePolicy etc. But these were already mentioned while I created NSURLSessionConfiguration. So if I use different values for a NSURLRequest, will those values override NSURLSessionConfiguration values?
In short, YES.
According to Apple's document:
In some cases, the policies defined in this configuration may be overridden by policies specified by an NSURLRequest object provided for a task. Any policy specified on the request object is respected unless the session’s policy is more restrictive. For example, if the session configuration specifies that cellular networking should not be allowed, the NSURLRequest object cannot request cellular networking.
My recollection is that yes, the value in the request takes precedence over the session's value. With that said, I'm not 100% certain, so I would try it and make sure, assuming it actually matters.

Architectural approach to HTTP communications and the parsing of returned JSON in iOS

Good evening guys,
My question is more of an engineering/design pattern approach than specifically technical.
I am developing an app that requires lots of interaction with a remote API returning JSON objects. The retrieval, parsing and utilisation of the data is not a problem and is working very smoothly. I am wanting to get some direction on the best design approach for this sort of scenario.
I will explain what I have so far (in pseudo code and declarations) and see if you can help:
A HTTP Fetcher class implementing the necessary NSURLConnection delegate methods. I initialise the class with the callback method selector like so for returning to the calling class on completion
#implementation HTTPFetcher{
- (id)initWithUrlRequest:(NSURLRequest *)aRequest receiver:(id)aReceiver action:(SEL)aReceiverAction
{
//set the member variables etc..
}
//all NSURLConnection delegate methods
- (void)connectionDidFinishLoading...
{
[receiver performSelector:action withObject:self];
}
}
I then have a Singleton HTTPController class for calling the HTTPFetcher:
- (void)postWithRequestString:(NSString *)aRequestString
{
[urlRequest setHTTPBody:[aRequestString dataUsingEncoding:NSUTF8StringEncoding]];
fetcher = [[HTTPFetcher alloc]initWithUrlRequest:urlRequest receiver:self action:#selector(receivedDataFromService:)];
[fetcher start];
}
- (void)receivedDataFromService:(HTTPFetcher *)aFetcher{
//handle the received data and split the parent object into an NSMutableDictionary
}
Now this approach works fantastically well for the app I have especially given the separate entities that I have to model (I will basically have a Singleton HTTPController for each entity).
My issue is where to handle the custom parsing of the JSON. Currently, I am doing the parsing the in ViewController where the data is required but this is too close to the source and needs to be abstracted out further but I am unsure how.
Should I include the methods to facilitate the parsing within the Singleton classes or should I create further controllers for parsing actions?
I look forward to hearing from you
Thanks
I would recommend you build on an existing JSON parsing library, in particular John Engelhart's JSONKit, considering it's arguably the highest performance JSON parsing library out there for iOS. Saves you implementing custom JSON parsing at all, but especially saves you implementing code which turns out to be too slow for your needs and then you will need to iteratively refine it until it gets fast enough for you to use.
For HTTP requests, I know you've implemented the behaviour already, but you might want to investigate ASIHTTPRequest or AFNetworking as general purpose networking libraries which have a reputation for being quite robust. Note AFNetworking uses the above JSONKit library for JSON parsing.
The way ASIHTTPRequest (the library I use in my projects) works is by using a delegate object implementing the protocol ASIHTTPRequestDelegate, which you assign after creating a request with a URL. There's a global network queue which is just an NSOperationQueue, and that handles asynchronous or multiple concurrent active requests.
You can setDelegate: for the object to start checking whether your delegate has implemented any of the methods at different points, such as didReceiveData: or requestDidFinish: by default, but you can also set a custom selector path to check by using the methods for individual operations (setDidFinishSelector:#selector(downloadComplete:)).
What you could do when, for example, the didReceiveData: callback happens, is pass the newly received data into a buffer stored in a wrapper class for an ASIJSONRequest (or use AFNetworking, which already encapsulates this). When the buffer is such that there is a complete JSON object in there which can be parsed correctly, then you call out to JSONKit to do the grunt work and then maybe send another callback yourself to an ASIJSONRequestDelegate for didReceiveData:, but now the data is in a format which is readable by the rest of your application.
Another method of using ASIHTTPRequest is with blocks. There is support for setting a completion block for a request, a block that is called when data is received, etc. For this design pattern you don't even need a wrapper class, just set the code block up to do the parsing itself and return any new data parsed to its desired destination.
One possibility would be for the View or view controller to ask a Model object for any state that it needs (including stuff from a remote server). The Model object would be told when there was any new data from the server, and it could then call any required data munging routines required to update its internal state (converting plists or json into a more canonical dictionary format, for instance).