Permalink
Browse files

Add backgrounding support

  • Loading branch information...
1 parent 3829e0b commit 0dc72e43173e5a813382e9e845bc33005c32df07 @bgfoshay bgfoshay committed Aug 24, 2013
Showing with 136 additions and 26 deletions.
  1. +104 −0 Source/TDReplicator+Backgrounding.m
  2. +3 −0 Source/TDReplicator.h
  3. +18 −25 Source/TDReplicator.m
  4. +10 −0 TouchDB.xcodeproj/project.pbxproj
  5. +1 −1 vendor/MYUtilities
@@ -0,0 +1,104 @@
+//
+// TDReplicator+Backgrounding.m
+// CouchbaseLite
+//
+// Created by Jens Alfke on 8/15/13.
+//
+//
+
+#if TARGET_OS_IPHONE
+
+#import "TDReplicator.h"
+#import "TDInternal.h"
+#import "MYBlockUtils.h"
+
+#import <UIKit/UIKit.h>
+
+
+@implementation TDReplicator (Backgrounding)
+
+
+// Called when the replicator starts
+- (void) setupBackgrounding {
+ _bgTask = UIBackgroundTaskInvalid;
+ [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appBackgrounding:)
+ name: UIApplicationDidEnterBackgroundNotification
+ object: nil];
+ [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appForegrounding:)
+ name: UIApplicationWillEnterForegroundNotification
+ object: nil];
+}
+
+
+- (void) endBGTask {
+ if (_bgTask != UIBackgroundTaskInvalid) {
+ [[UIApplication sharedApplication] endBackgroundTask: _bgTask];
+ _bgTask = UIBackgroundTaskInvalid;
+ }
+}
+
+
+// Called when the replicator stops
+- (void) endBackgrounding {
+ [self endBGTask];
+ [[NSNotificationCenter defaultCenter] removeObserver: self
+ name: UIApplicationDidEnterBackgroundNotification
+ object: nil];
+ [[NSNotificationCenter defaultCenter] removeObserver: self
+ name: UIApplicationWillEnterForegroundNotification
+ object: nil];
+}
+
+
+// Called when the replicator goes idle
+- (void) okToEndBackgrounding {
+ if (_bgTask != UIBackgroundTaskInvalid) {
+ LogTo(Sync, @"%@: Now idle; stopping background task (%d)", self, _bgTask);
+ [self stop];
+ }
+}
+
+
+- (void) appBackgrounding: (NSNotification*)n {
+ // Danger: This is called on the main thread! It switches to the replicator's thread to do its
+ // work, but it has to block until that work is done, because UIApplication requires
+ // background tasks to be registered before the notification handler returns; otherwise the app
+ // simply suspends itself.
+ NSLog(@"APP BACKGROUNDING");
+ MYOnThreadSynchronously(_thread, ^{
+ if (self.active) {
+ _bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{
+ // Called if process runs out of background time before replication finishes:
+ MYOnThreadSynchronously(_thread, ^{
+ LogTo(Sync, @"%@: Background task (%d) ran out of time!", self, _bgTask);
+ [self stop];
+ });
+ }];
+ LogTo(Sync, @"%@: App going into background (bgTask=%d)", self, _bgTask);
+ if (_bgTask == UIBackgroundTaskInvalid) {
+ // Backgrounding isn't possible for whatever reason, so just stop now:
+ [self stop];
+ }
+ } else {
+ LogTo(Sync, @"%@: App going into background", self);//TEMP
+ [self stop];
+ }
+ });
+}
+
+
+- (void) appForegrounding: (NSNotification*)n {
+ // Danger: This is called on the main thread!
+ NSLog(@"APP FOREGROUNDING");
+ MYOnThread(_thread, ^{
+ if (_bgTask != UIBackgroundTaskInvalid) {
+ LogTo(Sync, @"%@: App returning to foreground (bgTask=%d)", self, _bgTask);
+ [self endBGTask];
+ }
+ });
+}
+
+
+@end
+
+#endif // TARGET_OS_IPHONE
View
@@ -48,6 +48,9 @@ extern NSString* TDReplicatorStoppedNotification;
NSDictionary* _requestHeaders;
@private
TDReachability* _host;
+ #if TARGET_OS_IPHONE
+ NSUInteger /*UIBackgroundTaskIdentifier*/ _bgTask;
+ #endif
}
+ (NSString *)progressChangedNotification;
View
@@ -29,10 +29,6 @@
#import "MYBlockUtils.h"
#import "MYURLUtils.h"
-#if TARGET_OS_IPHONE
-#import <UIKit/UIApplication.h>
-#endif
-
#define kProcessDelay 0.5
#define kInboxCapacity 100
@@ -45,6 +41,13 @@
NSString* TDReplicatorProgressChangedNotification = @"TDReplicatorProgressChanged";
NSString* TDReplicatorStoppedNotification = @"TDReplicatorStopped";
+#if TARGET_OS_IPHONE
+@interface TDReplicator (Backgrounding)
+- (void) setupBackgrounding;
+- (void) endBackgrounding;
+- (void) okToEndBackgrounding;
+@end
+#endif
@interface TDReplicator ()
@property (readwrite, nonatomic) BOOL running, active;
@@ -239,10 +242,7 @@ - (void) start {
_startTime = CFAbsoluteTimeGetCurrent();
#if TARGET_OS_IPHONE
- // Register for foreground/background transition notifications, on iOS:
- [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appBackgrounding:)
- name: UIApplicationDidEnterBackgroundNotification
- object: nil];
+ [self setupBackgrounding];
#endif
_online = NO;
@@ -275,12 +275,7 @@ - (void) stop {
LogTo(Sync, @"%@ STOPPING...", self);
[_batcher flushAll];
_continuous = NO;
-#if TARGET_OS_IPHONE
- // Unregister for background transition notifications, on iOS:
- [[NSNotificationCenter defaultCenter] removeObserver: self
- name: UIApplicationDidEnterBackgroundNotification
- object: nil];
-#endif
+
[self stopRemoteRequests];
[NSObject cancelPreviousPerformRequestsWithTarget: self
selector: @selector(retryIfReady) object: nil];
@@ -293,6 +288,11 @@ - (void) stopped {
LogTo(Sync, @"%@ STOPPED", self);
Log(@"Replication: %@ took %.3f sec; error=%@",
self, CFAbsoluteTimeGetCurrent()-_startTime, _error);
+
+ #if TARGET_OS_IPHONE
+ [self endBackgrounding];
+ #endif
+
self.running = NO;
self.changesProcessed = self.changesTotal = 0;
[[NSNotificationCenter defaultCenter]
@@ -365,24 +365,17 @@ - (void) reachabilityChanged: (TDReachability*)host {
}
-#if TARGET_OS_IPHONE
-- (void) appBackgrounding: (NSNotification*)n {
- // Danger: This is called on the main thread!
- MYOnThread(_thread, ^{
- LogTo(Sync, @"%@: App going into background", self);
- [self stop];
- });
-}
-#endif
-
-
- (void) updateActive {
BOOL active = _batcher.count > 0 || _asyncTaskCount > 0;
if (active != _active) {
self.active = active;
[self postProgressChanged];
if (!_active) {
// Replicator is now idle. If it's not continuous, stop.
+ #if TARGET_OS_IPHONE
+ [self okToEndBackgrounding];
+ #endif
+
if (!_continuous) {
[self stopped];
} else if (_revisionsFailed > 0) {
@@ -359,6 +359,10 @@
27F1E4A61697995C00F0E50F /* TDJSViewCompiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F1E4A51697995C00F0E50F /* TDJSViewCompiler.m */; };
27F1E4A8169799DA00F0E50F /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27F1E4A7169799DA00F0E50F /* JavaScriptCore.framework */; };
27F1E4AB16979A0B00F0E50F /* TDJSViewCompiler_Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F1E4AA16979A0B00F0E50F /* TDJSViewCompiler_Test.m */; };
+ 3DF8DD6817C31C49002A1D91 /* TDReplicator+Backgrounding.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DF8DD6617C31C49002A1D91 /* TDReplicator+Backgrounding.m */; };
+ 3DF8DD6917C92AD2002A1D91 /* TDInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 279EB2D01491442500E74185 /* TDInternal.h */; };
+ 3DF8DD6A17C92AF2002A1D91 /* TDInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 279EB2D01491442500E74185 /* TDInternal.h */; };
+ 3DF8DD6B17C938C1002A1D91 /* TDReplicator+Backgrounding.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DF8DD6617C31C49002A1D91 /* TDReplicator+Backgrounding.m */; };
DA023B4614BCA94C008184BB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27F0745C11CD50A600E9A2AB /* Foundation.framework */; };
DA147C0C14BCA98A0052DA4D /* TDListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 275315DF14ACF0A20065964D /* TDListener.m */; };
DA147C0D14BCA98A0052DA4D /* TDHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 2753160B14ACFC2A0065964D /* TDHTTPConnection.m */; };
@@ -800,6 +804,7 @@
27F1E4AA16979A0B00F0E50F /* TDJSViewCompiler_Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TDJSViewCompiler_Test.m; path = ../Source/TDJSViewCompiler_Test.m; sourceTree = "<group>"; };
27F87BE61558890600F0A416 /* TDGNUstep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDGNUstep.h; sourceTree = "<group>"; };
27F87BE71558890700F0A416 /* TDGNUstep.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDGNUstep.m; sourceTree = "<group>"; };
+ 3DF8DD6617C31C49002A1D91 /* TDReplicator+Backgrounding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TDReplicator+Backgrounding.m"; sourceTree = "<group>"; };
8DD76F6C0486A84900D96B5E /* TouchDB */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TouchDB; sourceTree = BUILT_PRODUCTS_DIR; };
DA023B6414BCA94C008184BB /* libTouchDBListener.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTouchDBListener.a; sourceTree = BUILT_PRODUCTS_DIR; };
DA147C3614BCAC3B0052DA4D /* TouchDBListener.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TouchDBListener.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1208,6 +1213,7 @@
27C40C7714EC58BC00994283 /* TDReplicatorManager.h */,
27C40C7814EC58BC00994283 /* TDReplicatorManager.m */,
27B0B78F149290AB00A817AD /* ChangeTracker */,
+ 3DF8DD6617C31C49002A1D91 /* TDReplicator+Backgrounding.m */,
);
name = Replicator;
sourceTree = "<group>";
@@ -1577,6 +1583,7 @@
27E41530154F6E9C00771FC5 /* TDStatus.h in Headers */,
27F08C8A15A7A30D003C3E2B /* TD_DatabaseManager.h in Headers */,
27F08C8B15A7A31B003C3E2B /* TD_Attachment.h in Headers */,
+ 3DF8DD6917C92AD2002A1D91 /* TDInternal.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1585,6 +1592,7 @@
buildActionMask = 2147483647;
files = (
DA147C3E14BCAC9D0052DA4D /* TDListener.h in Headers */,
+ 3DF8DD6A17C92AF2002A1D91 /* TDInternal.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2090,6 +2098,7 @@
27F128B9156AC8F0008465C2 /* OAMutableURLRequest.m in Sources */,
270F5702156AD215000FEB8F /* OARequestParameter.m in Sources */,
2776A5D616A61FD6006FF199 /* TDPersonaAuthorizer.m in Sources */,
+ 3DF8DD6817C31C49002A1D91 /* TDReplicator+Backgrounding.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2150,6 +2159,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 3DF8DD6B17C938C1002A1D91 /* TDReplicator+Backgrounding.m in Sources */,
27B0B7CD1492B86C00A817AD /* TD_Database.m in Sources */,
27B0B7CE1492B86F00A817AD /* TD_View.m in Sources */,
27B0B7CF1492B87200A817AD /* TD_Body.m in Sources */,

0 comments on commit 0dc72e4

Please sign in to comment.