iOS job queue similar to Path's android priority job queue - ios

Does anyone have an iOS job queue similar to Path's Android Priority Job Queue that they don't mind sharing with the community? I am very new to iOS so I am not sure if the platform itself provides such a solution. On android no such thing exists so I had to use the library that Path has generously made available. If iOS itself or Xcode has such a solution/API please point me to it. If not please share yours if you don't mind. Thanks.
Basically I am looking for a job queue that can allow users to send data to server even when there is no network: which means the queue would hold on to the data even if user should turn off the iPhone. And then at some later time, when the system detects network, push the data to the server.
There is a similar question on SO already so I am including it for more detail: How to queue up data for server dispatch on android. The difference is that my question is for iOS and theirs is for android.
Use case
My case is imagining a user is boarding a train in a subway (no network) but decides to send an email. Then close the app, or even turn off the phone. Then an hour later, after user turns phone back on, when network is detected, the app sends the email.

https://github.com/thisandagain/queue is quite promising. It has ability to retry and is persistent.

AFNetworking's request operations and request operation manager could be modified to do this with not too much work.
Needed modifications:
When an AFHTTPRequestOperation fails due to no connectivity, make a copy of the operation and store it (in an NSArray, for example)
Use the built-in reachability manager, and retry the operations in the array when reachability returns
Remove the operations from the array if they're successful
Note that the completion blocks aren't copied when an operation is copied. From the documentation:
-copy and -copyWithZone: return a new operation with the NSURLRequest of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations.
A copy of an operation will not include the outputStream of the original.
Operation copies do not include completionBlock, as it often strongly captures a reference to self, which would otherwise have the unintuitive side-effect of pointing to the original operation when copied.
I don't know of any open source library that has already implemented these modifications, or I'd point you there.

I found very simmilar lib like path's job priority queue
https://github.com/lucas34/SwiftQueue/wiki
Hope this helps someone since this is very old questions but ot might help someone who is still finding like me :)

Related

Can RealmCollectionChange be used as a way of syncing data back to server?

I noticed that in Realm Swift, there is a RealmCollectionChange
https://realm.io/docs/swift/latest/#realm-notifications
It seems to contain the objects that have changed. Can I use that notification block to add code to sync the data back to a back end database?
Is the notification block running on the main queue?
For sure you can use the provided notification mechanisms to propagate changes to a server. You should make sure though, that your requests to the server doesn't cause new changes once the server responds, otherwise you can run into a situation where you would be constantly notified about new updates, as also seen in the related docs section User-Driven Updates.
The notification block is ran on the thread on which you add it. But these APIs are only available to auto-updating Realms which require a runloop. By default only the main thread has a runloop, if you don't run any additional yourself on dedicated background threads.
Be aware that synchronizing is a non-trivial problem and using these notifications alone won't give you a full solution for every challenge involved into that problem space.

iOS NSURLSession waits for timeout if server doesn't exist

We use an NSURLSession to download data in the background, and have timeoutIntervalForResource defined so it will timeout if it takes too long, but if, for whatever reason, the source server doesn't exist then it still sits and waits. Is there any way to get it to abort immediately, or 'ask' the NSURLSessionDownloadTask if anything has been downloaded yet?
Failing that, what would be the best way of performing a pre-check to ensure a server exists before trying to download data from it?
These servers may be out of our control so we can't place a small file to download to check availability. The only file we may not about could be a sizeable video, for example.
You can indeed ask the task about its status. First, check the response property. If that is nil, then you haven't gotten the first packet from the server. If that is non-nil, use countOfBytesExpectedToReceive and countOfBytesReceived as needed to determine progress.
I should also note that these properties all support KVO, AFAIK.
You could also perform an explicit DNS lookup prior to scheduling the background request if you'd prefer, with the caveat that doing so would prevent you from scheduling something that might actually work if the user's Internet connection comes back online in the meantime. :-)

Async logging of a static queue in Objective-C

I'd like some advice on how to implement the following in Objective C. The actual application in related to an AB testing framework I'm working on, but that context shouldn't matter too much.
I have an IOS application, and when a certain event happens I'd like to send a log message to a HTTP Service endpoint.
I don't want to send the message every time the event happens. Instead I'd prefer to aggregate them, and when it gets to some (configurable) number, I'd like to send them off async.
I'm thinking to wrap up a static NSMutableArray in a class with an add method. That method can check to see if we have reached the configurable max number, if we have, aggregate and send async.
Does objective-c offer any better constructs to store this data? Perhaps one that helps handle concurrency issues? Maybe some kind of message queue?
I've also seen some solutions with dispatching that I'm still trying to get my head around (I'm new).
If the log messages are important, keeping them in memory (array) might not suffice. If the app quits or crashes the NSArray will not persist on subsequent execution.
Instead, you should save them to a database with an 'sync' flag. You can trigger the sync module on every insert to check if the entries with sync flag set to false has reached a threshold and trigger the upload and set sync flag to true for all uploaded records of simply delete the synced records. This also helps you separate your logging module and syncing module and both of them work independently.
You will get a lot of help for syncing SQLite db or CoreData online. Check these links or simply google iOS database sync. If your requirements are not very complex, and you don't mind using third party or open source code, it is always better to go for a readily available solution instead of reinventing the wheel.

Using GCD for offline persistent queue

Right now I have some older code I wrote years ago that allows an iOS app to queue up jobs (sending messages or submitting data to a back-end server, etc...) when the user is offline. When the user comes back online the tasks are run. If the app goes into the background or is terminated the queue is serialized and then loaded back when the app is launched again. I've subclassed NSOperationQueue and my jobs are subclasses of NSOperation. This gives me the flexibility of having a data structure provided for me that I can subclass directly (the operation queue) and by subclassing NSOperation I can easily requeue if my task fails (server is down, etc...).
I will very likely leave this as it is, because if it's not broke don't fix it, right? Also these are very lightweight operations and I don't expect in the current app I'm working on for there to be very many tasks queued at any given time. However I know there is some extra overhead with using NSOperation rather than using GCD directly.
I don't believe I could subclass a dispatch queue the way I can an NSOperationQueue, so there would be extra code overheard for me to maintain my own data structure and load this into & out of a dispatch queue each time the app is sent to the background, right? Also not sure how I'd handle requeueing the job if it fails. Right now if I get a HTTP 500 response from the server, for example, in my operation code I send a notification with a deep copy of the failed NSOperation object. My custom operation queue picks this notification up and adds the task to itself. Not sure how of if I'd be able to do something similar with GCD. I would also need an easy way to cancel all operations or suspend the queue when network connectivity is lost then reactivate when network access is regained.
Just hoping to get some thoughts, opinions and ideas from others who might have done something similar or are more familiar with GCD than I am.
Also worth noting I know there's some new background task support coming in iOS 7 but it will likely be a while before that will be my deployment target. I am also not sure yet if it would exactly do what I need, so at the moment just looking at the possibility of GCD.
Thanks.
If NSOperation vs submitting blocks to GCD ever shows up as measurable overhead, the problem isn't that you're using NSOperation, it's that your operations are far too granular. I would expect this overhead to be effectively unmeasurable in any real-world situation. (Sure, you could contrive a test harness to measure the overhead, but only by making operations that did effectively nothing.)
Use the highest level of abstraction that gets the job done. Move down only when hard data tells you that you should.

NSURLConnection and multiple asynchronous requests - is it messing with the data being transmitted?

I have an NSArray of links. I want to parse through them with an online article extractor API (Clear Read), and with the result given back for each article (some HTML) I throw it into an NSString.
My problem arises from the fact that, say my array has 100 URLs in it, I loop through the array shooting each item into the API and getting back some results in JSON. This is firing like 100 NSURLConnection calls at once asynchronously.
I wasn't sure if that'd be a problem, but when I give it 100 URLs (real strings, none are nil) the data that comes back often has either empty values for the JSON keys (when they shouldn't), or the data coming back is nil. There's also a bunch of duplicates.
Should I be handling multiple asynchronous connections better than I am now? If so, how?
A couple of thoughts:
If you're doing concurrent asynchronous requests and are using asynchronous NSURLConnection, then you'll want to define your own class for this download operation to make sure that every connection keeps track of its own properties. That way, everything can be encapsulated within this class where the resulting download objects can keep track of what's downloaded, what's been parsed, etc. If you're not using asynchronous NSURLConnection (e.g. you're just using dataWithContentsOfURL), it's even easier, though you lose some of the progress updates that NSURLConnection provides and/or streaming opportunities.
For best performance, you should do concurrent requests. Having said that, you should not have more than four or five concurrent requests going to any particular server. This is an iOS imposed constraint, and especially if you have a slow network connection, you risk having connections timeout otherwise.
If you're doing preliminary testing on the simulator, you may want to make sure you try out the "network link conditioner". It's part of the "Hardware IO Tools for Xcode", available at the Downloads for Apple Developers. There are issues (such as the aforementioned timeout problems if you have too many concurrent requests going to a particular server) that only manifest themselves in slow connections.
Having said that, you also want to make sure to test your solution on a device with real world network speeds. It's easy to successfully run massively parallel tasks successfully on the simulator that are too greedy for the device. Limiting the number of concurrent sessions to five will diminish this resource problem, but it should be part of your testing strategy.
I agree with JRG-Developer, that you should look into established frameworks, such as AFNetworking. Make sure to set the maxConcurrentOperationCount for the queue of the AFHTTPClient, though, if queueing 100 plus operations.
I don't know how much data your 100 requests entail, but be forewarned that the app approval process has been known to reject apps that make extraordinary networks requests on cellular networks. What constitutes excessive cellular network activity is not explicitly stated in the app review guidelines, though Avoiding iPhone App Rejection From Apple has claimed that you should ensure that you don't exceed more than 4.5mb in 5 minutes. You can use Reachability to determine what type of network you are on and perhaps warn the user if they're on cellular (if the amount of data approaches this threshold).
Have you considered using a third party framework - such as AFNetworking - and limiting the number of asynchronous calls happening at once? Perhaps this might help / solve your problem.
In particular, you might consider creating a networking manager class that creates and manages AFHTTPClient(s), which in turn manages AFHTTPRequestOperations, for each endpoint (base URL) you hit.

Resources