12

I have a JSON file populated with strings data in Documents Directory. In user Interface of application there is a UIButton. On button press, a new string appends into the JSON file.

Now I am looking for any iOS Service that helps me to send these strings (from JSON file) to the server using swift. And this service should be totally independent of my code. The point is when I press a UIButton, the first step is a string is saved to the JSON file then service should take this string and send it to server if Internet is available.

When a string sent successfully, it should be removed from the JSON file. This service should track after every 30 seconds if there is any string saved into JSON file, then send it to server.

I Googled and found background fetch but It triggers performFetchWithCompletionHandler function automatically and I cannot know when iOS triggers it. I want to trigger this kind of service my self after every 30 seconds.

JAL
  • 39,073
  • 22
  • 153
  • 285
user3314286
  • 243
  • 3
  • 17
  • Did you found some solution for your request? Thanks! – Joan Casadellà Sep 13 '16 at 09:27
  • 1
    how / why would it be independent of your app? – Wain Sep 13 '16 at 10:13
  • 2
    If you're looking for a daemon/service, then you're out of luck, iOS doesn't support custom apps that indefinitely run. – Cristik Sep 19 '16 at 18:35
  • Thank you every body I have solved my problem by just using NSTimer with time interval function, which calls my own created syncService class methods after every 30 secs – user3314286 Sep 20 '16 at 10:36
  • @xikitidistant did my answer help you? It looks like it helped the OP. – JAL Sep 20 '16 at 14:14
  • yes @xikitidistant your answer provides a same approach That I have used. One more Thing is that I had solved my problem early than you with the same functions `application.beginBackgroundTask` `application.endBackgroundTask` you provided. But you posted an Answer early than me This is why I have Tic marked your Answer. You can also see my Answer posted below. Thank you again jal – user3314286 Sep 21 '16 at 10:26

5 Answers5

12

Review the Background Execution portion of Apple's App Programming Guide for iOS.

UIApplication provides an interface to start and end background tasks with UIBackgroundTaskIdentifier.

In the top level of your AppDelegate, create a class-level task identifier:

var backgroundTask = UIBackgroundTaskInvalid

Now, create your task with the operation you wish to complete, and implement the error case where your task did not complete before it expired:

backgroundTask = application.beginBackgroundTaskWithName("MyBackgroundTask") {
    // This expirationHandler is called when your task expired
    // Cleanup the task here, remove objects from memory, etc

    application.endBackgroundTask(self.backgroundTask)
    self.backgroundTask = UIBackgroundTaskInvalid
}

// Implement the operation of your task as background task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    // Begin your upload and clean up JSON
    // NSURLSession, AlamoFire, etc

    // On completion, end your task
    application.endBackgroundTask(self.backgroundTask)
    self.backgroundTask = UIBackgroundTaskInvalid
}
JAL
  • 39,073
  • 22
  • 153
  • 285
  • 1
    Note that this will execute in the foreground if the app is not backgrounded until the work finishes. – Cristik Sep 19 '16 at 18:06
  • Great point @Cristik. I think this is the closes solution to what the OP is asking for due to Apple restrictions. – JAL Sep 19 '16 at 19:17
  • Thanks friend I have already solved my problem by the same approach you provided. – user3314286 Sep 20 '16 at 11:08
4

What I have done is I just uses the approach discussed by JAL above.

these were the three methods which I used

    func reinstateBackgroundTask() {
        if updateTimer != nil && (backgroundTask == UIBackgroundTaskInvalid) {
            registerBackgroundTask()
           }
    }
    func registerBackgroundTask() {
        backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
            [unowned self] in
            self.endBackgroundTask()
        }
        assert(backgroundTask != UIBackgroundTaskInvalid)
    }

    func endBackgroundTask() {
        NSLog("Background task ended.")
        UIApplication.sharedApplication().endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
    }

where updateTimer is of type NSTIMER class The above functions are in my own created class named "syncService" This class has an initialiser which is

init(){
  NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.reinstateBackgroundTask), name: UIApplicationDidBecomeActiveNotification, object: nil)

        updateTimer = NSTimer.scheduledTimerWithTimeInterval(30.0, target: self, selector: #selector(self.syncAudit), userInfo: nil, repeats: true)
        registerBackgroundTask()

 }

Then I just called this class and the whole problem is solved.

user3314286
  • 243
  • 3
  • 17
3
 DispatchQueue.global(qos: .background).async { // sends registration to background queue

 }
Aditya Sharma
  • 485
  • 4
  • 18
1

Please refer NSURLSessionUploadTask might it help you.

Kiran K
  • 877
  • 10
  • 17
0

Here is the swift 4 version of the answer by JAL

  extension UIApplication {
  /// Run a block in background after app resigns activity
   public func runInBackground(_ closure: @escaping () -> Void, expirationHandler: (() -> Void)? = nil) {
       DispatchQueue.main.async {
        let taskID: UIBackgroundTaskIdentifier
        if let expirationHandler = expirationHandler {
            taskID = self.beginBackgroundTask(expirationHandler: expirationHandler)
        } else {
            taskID = self.beginBackgroundTask(expirationHandler: { })
        }
        closure()
        self.endBackgroundTask(taskID)
    }
  }

  }

Usage Example

UIApplication.shared.runInBackground({
        //do task here
    }) {
       // task after expiration.
    }
levin varghese
  • 660
  • 11
  • 12