NIKITA TUKiOS Developer, Coins.ph Toptal Speakers Network
Handling background processes in iOS:
problems & solutions
Yandex.Disk
Autoupload Offline
• The App Life Cycle before iOS7 • The App Life Cycle on iOS now • Experiments & limitations • Testing • Our approach
Agenda
Not Running
ForegroundSuspended
Background
Not Running
ForegroundSuspended
Background
NSURLSession Silent notifications
Background Fetch
Silent notificationsaps { content-available: 1 alert: {...} sound: ... badge: ... }
30 sec
Background fetch <key>UIBackgroundModes</key> <array> <string>fetch</string> </array> 30 sec
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
NSURLConnection
ConnectionConfiguration
ConnectionConfiguration
ConnectionConfiguration
NSURLSessionNSURLSession
Configuration
NSURLSessionTask
NSURLSessionTask
NSURLSessionTask
NSURLSessionDataTask
NSURLSessionUploadTask
NSURLSessionDownloadTaskNSURLSessionStreamTask
background
background
nsurlsessiond
Behind the scenes
task
task
30 sec
Behind the scenesfunc application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
enum UIBackgroundFetchResult: UInt { case newData case noData case failed }
Experiments
iOS8 iOS10
• Call completion handler as early as possible • Save battery life • Always call completion handler
Experiments
Experiments
00pm 03am 06am 09am 12am 03pm 06pm 09pm
Experiments
00pm 03am 06am 09am 12am 03pm 06pm 09pm 11pm
Experiments
00pm 03am 06am 09am 12am 03pm 06pm 09pm 11pm
Limitations
Push notifications
Limitations
Testing
Charles
Testingprotocol URLSessionDataTaskProtocol { func resume() }
extension NSURLSessionDataTask: URLSessionDataTaskProtocol { }
protocol URLSessionProtocol { func dataTaskWithURL(url: NSURL, completionHandler: DataTaskResult) -> URLSessionDataTaskProtocol }
extension NSURLSession: URLSessionProtocol { func dataTaskWithURL(url: NSURL, completionHandler: DataTaskResult) -> URLSessionDataTaskProtocol { return (dataTaskWithURL(url, completionHandler: completionHandler) as NSURLSessionDataTask) as URLSessionDataTaskProtocol } }
Testingclass APIManager { private let session: URLSessionProtocol init(session: URLSessionProtocol) { self.session = session ... }
// Tests:let manager = APIManager(session: MockURLSession)
// App: let manager = APIManager(session: RealURLSession)
Our approach• Photos framework challenges • Uploading state machine • Modular architecture • Ensuring completion handler invocation • App restoration
Photos framework challenges// Creates an upload task with the given request. The body of the request will be created from the file referenced by fileURL func uploadTask(with request: URLRequest, fromFile fileURL: URL) -> URLSessionUploadTask
PHAsset • no URL • can be burst/live photo • can have filters (stored as original photo + delta) • need to calculate hash before uploading • can be stored in iCloud
Photos framework challenges// Copy PHAsset to sandbox PHAssetResourceManager.default().writeData(for: resource, toFile: filePathURL, options: options) { error in completion(error) }
Calculating PHAsset hash before uploading/uploading by chunks
OR
Uploading state machine
Modular architecture
NSURLSession NSURLSession NSURLSession
Data Upload (background)
Download (background)
Ensuring completion handler invocation
// Remote notifications func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
// Tells the delegate that events related to a URL session are waiting to be processed.func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void)
// Tells the app that it can begin a fetch operation if it has data to download.func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
Completion manager
nsurlsessiond
App restoration
task
Another session
var taskDescription: String
WWW.MDEVTALK.CZ
mdevtalk