Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use background task using Swift 3?

I am new in background tasks. I have a small work that I am fetching tweets and If my app is in background mode then also it should fetch tweets, but I don't know how.

I am using simply Timer in Appdelegate didFinishLaunchOption Method. When I will close the app then it's not working. I am new in that so please any suggestion. Here below is my code:

Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(getTweets), userInfo: nil, repeats: true). 

func getTweets() {

    let locationName = Helper.sharedInstance.userDefault.value(forKey: ModelKey.currentLocation) as? String

    let accessToken = Helper.sharedInstance.userDefault.value(forKey: ModelKey.twitterAccessToken) as? String

    if (locationName == "Bengaluru" && nil != accessToken) || (locationName == "Bangalore" && nil != accessToken){
        tweetModel.getTweets(accessToken: accessToken!, city: ModelKey.blrcitytraffic, cityName: "Bengaluru")
    }
}

Text to speech is also there but when I will close the app then it stops speaking. If I am not using app then also it can fetch tweets and text to speech should work using a background mode. How long does that work?

like image 403
Kishor Pahalwani Avatar asked Jul 19 '17 13:07

Kishor Pahalwani


2 Answers

A background task means you need to use background threads. Threads in iOS are too many, but if you want to make only background task, you should use two threads; the main and background thread that their structure is:

DispatchQueue.global(qos: .background).async {
    //background code
    DispatchQueue.main.async {
        //your main thread
    }    
}

So, you firstly initialize the global queue with background mode. This thread can be used for background task and then you must use main thread (only if you want) for doing something when the background task is finished. This can be an option. Another option should be applicationDidEnterBackground in appDelegate and you can only must put your code in that method.

like image 124
Alfredo Luco G Avatar answered Oct 19 '22 15:10

Alfredo Luco G


You need to do three things:

  1. In your Info.plist add the following entry for key Required background modes to allow background network access:

    Required background modes: App downloads content from the network

  2. In your AppDelegate add to your applicationDidEnterBackground():

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Fetch no sooner than every (60) seconds which is thrillingly short actually. 
        // Defaults to Infinite if not set. 
        UIApplication.shared.setMinimumBackgroundFetchInterval( 60 ) )
    }
    
  3. Also in AppDelegate implement

    func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
      var fetchResult: UIBackgroundFetchResult!
    
    
      if doingYourStuffActuallyCreatesNetworkTraffic() {
        fetchResult = UIBackgroundFetchResult.newData
      } else if thereWasAnError() { 
        fetchResult = UIBackgroundFetchResult.failed
      } else {
        fetchResult = UIBackgroundFetchResult.noData
      }           
      completionHandler( fetchResult )
    
      return    
    }
    

There are still some pitfalls, e.g. there is no guaranteed maximum fetch interval, and background execution might behave substantially different in XCode/Simulator than on real devices.

You could take a look at this pretty similiar topic:

performFetchWithCompletionHandler never gets fired

and of course https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

like image 42
christian.buggle Avatar answered Oct 19 '22 15:10

christian.buggle