I'm not sure exactly how to correctly construct my question. It is actually more of a "what is the advised practice" instead of an "how to" type of question. So I'll try to explain my main goal first.
I've started writing a small app which allows users to fill out forms and send them to a server. But the connectivity is a real problem. Often there are times that these filled out forms must be saved on the device until wi-fi is available again.
The app has multiple view controllers, each with different jobs as you can imagine. I am thinking of writing a class which will be initialized during the app launch and will continue to run through out the apps whole life cycle. This class will periodically check for an internet connection and when available, upload saved forms to the server and than remove them from local core data database.
I've read about the background tasks, singletons, app delegate functions, global functions etc. And honestly I am confused. Every article and/or post I've read criticizes the other method with no one noting the correct way of doing this. "Globals are bad", "singletons are evil", "don't use app delegate" etc... I'm not sure what is the advised practice to achieve this.
Can we please discuss what is the preferred way to write a "self contained, periodic check and upload function" which is independent from any viewcontroller and will run in the background during apps whole life cycle.
Related
Would it be resource intensive to create a new URLSession for every single web request?
Some background:
I'm working on a library for making web requests. I'm trying to add a feature that allows downloading the result to a file that would also report its progress. For that, I'm going to have to become the session's delegate.
This wouldn't be a big deal except the public interface allows customizing the URLSession used for the requests. I don't want to override any customization the developer wants to do with its own delegate.
Right now, I'm thinking that the way to do this would be to secretly make a copy of the session they think is being used (yes I'm going to do more than copy the object itself) and then my internal delegate would call out to the original public session's methods. There could still be confusion/problems if they try to manipulate the session during the request, but that seems like a much smaller edge case.
My only concern right now is this might be very resource intensive if many requests are being made. Does anyone have a sense for that?
Yes, they are intensive. Here is a quote from Apple Staff on the developer forums.
This is a common anti-pattern, one that we specifically
warned against at at WWDC this year. Creating a session per request
is inefficient both on the CPU and, more importantly, on the network.
Specifically, it prevents connection reuse, which can radically slow
down back-to-back requests. This is especially bad for HTTP/2. We
encourage folks to group all similar tasks in a single session, using
multiple sessions only if you have different sets of tasks with
different requirements (like interactive tasks versus background
download tasks). That means that many simple apps can get away with
using a single statically-allocated session.
Good day, everyone, I'm new to iOS development, programming in general actually, quick question, will my APP get approved if it does not has data persistence?
It's a quick and small text manipulation kind of APP, it reads the data, process it, then done with it (send out the results via email), I just don't see the needs of doing persistence, and also, the model is basically being put in the appDelegate, for each tabBarController to work with. Everything works just the way I expected, not sure if that's (no data persistence + use appDelegate to keep shared model) really and could get my APP rejected?
Thanks for your time answering my questions :)
The short answer: No. Your app will not get rejected.
Apps that's get rejected are usually violating something serious, like consuming to much CPU, calling Apples private APIs, responding to user input in an unpredictable manner or simply crashing etc - not just code design issues.
It sounds however like you should consider moving your model some place else, for the sake of ease the maintenance of your code.
Consider creating a modelClass that implements the Singleton pattern. The purpose and responsibility of the AppDelegate should be limited to starting up your app and controlling its lifecycle
I am trying to build an offline synchronization capability into my iOS App and would like to get some feedback/advice from the community on the strategy and best practice to be followed to do the same. The app details are as follows:
The app shows a digital catalog to users and allows them to perform actions like creating and placing orders, among others.
Currently the app only works when online, and we have APIs for all actions like viewing the catalog, creating/placing orders which return JSON data.
We would like to provide offline/synchronization capability to users, through which users can view the catalog and create/place orders while offline, and when they come online the order details will be synchronized and updated to our server.
We would also like to pull the latest data from the server, and have the app keep itself up to date in case of catalog changes or order changes that happened at the Server while the app was offline.
Can you guys help me to come with the best design and approach for handling this kind of functionality?
I have done something similar just in the beginning of this year. After I read about NSOperationQueue and NSOperation I did a straight forward approach:
Whenever an object is changed/added/... in my local database, I add a new "sync"-operation to the queue and I do not care about, if the app is online or offline (I added a reachability observer which either suspended the queue or takes it back working; of course, I do re-queueing if an error occurs (lost network during sync)). The operation itself reads/writes the database and does the networking stuff. My ViewController use a NSFetchedResultsController (with delegate=self) to get callbacks on changes. In some cases I needed some extra local data (it is about counting objects), where I have used NSManagedObjectContextObjectsDidChangeNotification.
Furthermore, I have used Multi-Context CoreData which sounded quite reasonable to use (I have only two contexts).
To get notified about changes from your server, I believe that iOS 7 has something new for you.
On the server side, you should read a little for the actual approach you want to go for: i.e. Data Synchronization by Dan Grover or Developing Android REST Client Applications (of course there are many more good articles out there).
Caution: you might be disappointed when you expect an easy solution. Your requirement is not unusual, but the solution might become more complex than you expect - depending on the "business rules" and other reasonable requirements. If you intelligently restrict your requirements you may find a solution which you can implement yourself, otherwise you may also consider to use a commercial product.
I could imagine, that if you design the business logic such that it takes an offline state into account and exposes this explicitly in the business logic, you may find a solution which you can implement yourself with moderate effort. What I mean by this is for example, when a user creates an order, it is initially in "not committed" stated. The order will only be committed when there is access to the server and if the server gives the "OK" that this order can actually be placed by this user. The server may also deny the order, sending corresponding messages to the user.
There are probably quite a few subtle issues that may arise due to the requirement of eventual consistency.
See also this question which contains pointers to solutions from commercial products, and if you visit their web sites give valuable information about the complexity of the problem and how this can be solved.
I'm developing an application that processes a real time data feed across the internet. There are 2 fundamentally different things I want to do with it: one extremely simple but critical that it never is interrupted. Another much more complex but interruption is not such a horrible problem. Given that the second would have higher risk of the application crashing due to its complexity... I'm asking if there is some way that both can be receiving the data feed at the same time?
I could have both functions in a single application but if it crashes, that's very bad. I was thinking by separating the two functions into two applications, it might provide more robust handling for the critical simple processing.
But if I separate into two applications, is it possible for both of them to receive the identical data at the same time? Some type of OS networking voodoo or something?
It depends on the stream and on the way you want to implement it - some general ideas to achieve what you describe:
make a receiver app
this has the only purpose in receiving the feed and dispatching it to any apps/consumers who register to receive... if the receiving apps are on the same system you can use shared memory (MemoryMappedFile in .NET for example) which is really fast... this would help regarding future requirements - for example if you need to implement another processing app it just needs to register with the receiver app... another nice side-effect: the receiver app can capture the feed to some persistence and thus allow a "replay" for testing purposes etc.
make the "critical" one multiplex the feed
this would mean only your critical app receives the feed and sends a copy to the other app (for example on a different thread)
I've been reading up on SQLite3 included in the iOS firmware which might serve my needs for the app i'm writiung.
What I can't figure out is if it is persistent or goes away like some objects do.
For example if I do sqlite3_open() which appears to be a C function rather than an Objective-C object, if I open this at the start of my application, will it stay persistent until I close it no matter how many views I push/pop all over the place.
Obviously that would depend on where I put it but if I was doing a universal app and had some central functions for loading / saving data which were common to both iPhone/iPad, if, in my didFinishLoading: I put a call to open the SQLite database and then called various exec's of queries, would it remain persistent throughout the lifecycle of the application.
or
Am I better off opening and closing as needed, i'm coming from a PHP background so i'd normally open a database at the start of the script and then run many queries and then finally close it before browser output.
From the 1,000,000th i've learned over the last few months about iOS programming, I think the latter might be the better way as there's possibility of app exit prematurely or it going to background.
I'd just like a second opinion on my thinking please.
I dont know directly, but I think you are right - you only need to open it once at the start of your app.
Looking at sqlitepersistentobjects, an ORM framework for iOS, it only opens the DB when its first used, and never closes it except when there is a problem opening it :)
Single opened sqlite database used throughout the app from different places in your app is fine.
You are using word "persistent" which is confusing. What you mean is "reuse of single connection, for executing different statements in the app, possibly from different threads". Persistence has completely different meaning in context of databases - it means that the requested modification of data has been safely stored to media (disk, flash drive) and the device can even unexpectedly shut down without affecting written data.
It's recommended to keep running sqlite statements from a single, dedicated thread.
It's not recommended to connect to sqlite database from different processes for and executing parallel modifications.
A good alternative solution is to use sqlite async extension which sends all writes to a dedicated, background thread.
You can check out https://github.com/mirek/CoreSQLite3 framework if you want to use custom built (newer version) of sqlite.