@@ -34,54 +34,115 @@ - (id)init
3434{
3535 if (self = [super init ]) {
3636 _defaults = [NSUserDefaults standardUserDefaults ];
37- _requests = [self loadRequests ];
37+ [self migrateRequests ];
3838 }
3939 return self;
4040}
4141
42- - (NSMutableArray *)loadRequests
42+ + (LPRequestStorage *)sharedStorage
43+ {
44+ static LPRequestStorage *_sharedStorage = nil ;
45+ static dispatch_once_t sharedStorageToken;
46+ dispatch_once (&sharedStorageToken, ^{
47+ _sharedStorage = [[self alloc ] init ];
48+ });
49+ return _sharedStorage;
50+ }
51+
52+ /* *
53+ * Handle migration from old saving methods.
54+ * List of migrations:
55+ * 1) Moving away from NSUserDefaults. iOS8 introduced a performance hit that made it
56+ * unusable. Introduced saving to file as plist. Safe to remove from April 2015.
57+ * 2) Previously it was saving to the cache directory. Moving it to documents. (1.5.0)
58+ */
59+ - (void )migrateRequests
4360{
44- NSMutableArray *requests = [NSMutableArray array ];
4561 @synchronized (self) {
46- // For compatibility with older SDKs .
47- // TODO: Remove in April 2015.
48- NSInteger count = [_defaults integerForKey: LEANPLUM_DEFAULTS_COUNT_KEY];
49- for ( NSInteger i = 0 ; i < count; i++) {
50- NSString * itemKey = [LPRequestStorage itemKeyForIndex: i];
51- NSDictionary * requestArgs = [_defaults dictionaryForKey: itemKey ];
52- if (requestArgs != nil ) {
53- [requests addObject: requestArgs] ;
62+ // Move old cached directory to documents directory .
63+ NSError *error;
64+ if ([[ NSFileManager defaultManager ] fileExistsAtPath: self .cacheFilePath]) {
65+ [[ NSFileManager defaultManager ] moveItemAtPath: self .cacheFilePath
66+ toPath: self .documentsFilePath
67+ error: &error ];
68+ if (error ) {
69+ LPLog (LPVerbose, @" Error in moving stored requests: %@ " , error) ;
5470 }
5571 }
56-
57- if (!count) {
58- // Backwards compatible with old cached directory
59- NSError *error ;
60- if ([[ NSFileManager defaultManager ] fileExistsAtPath: self .cacheFilePath] ) {
61- [[ NSFileManager defaultManager ] moveItemAtPath: self .cacheFilePath
62- toPath: self .documentsFilePath
63- error: &error ];
64- if (error ) {
65- LPLog (LPVerbose, @" Error in moving stored requests: %@ " , error) ;
72+
73+ // For compatibility with older SDKs.
74+ NSMutableArray *requests = [ NSMutableArray array ];
75+ NSInteger count = [_defaults integerForKey: LEANPLUM_DEFAULTS_COUNT_KEY] ;
76+ if (count ) {
77+ for ( NSInteger i = 0 ; i < count; i++) {
78+ NSString *itemKey = [LPRequestStorage itemKeyForIndex: i];
79+ NSDictionary *requestArgs = [_defaults dictionaryForKey: itemKey ];
80+ if (requestArgs ) {
81+ [ requests addObject: requestArgs] ;
6682 }
83+ [_defaults removeObjectForKey: itemKey];
6784 }
68- NSData *requestData = [NSData dataWithContentsOfFile: self .documentsFilePath];
69- if (requestData) {
70- error = nil ;
71- NSMutableArray *savedRequests = [NSPropertyListSerialization
72- propertyListWithData: requestData
73- options: NSPropertyListMutableContainers
74- format: NULL error: &error];
75- if (savedRequests) {
76- requests = savedRequests;
77- }
85+ [_defaults removeObjectForKey: LEANPLUM_DEFAULTS_COUNT_KEY];
86+ [_defaults synchronize ];
87+ if (![[NSFileManager defaultManager ] fileExistsAtPath: self .documentsFilePath]) {
88+ [self saveRequests: requests];
7889 }
7990 }
8091 }
92+ }
8193
82- LPLog (LPDebug, @" Loaded %lu requests" , (unsigned long ) requests.count );
94+ /* *
95+ * Save requests to documents directory as a plist format.
96+ * Make sure to wrap this call with synchronize to support multi-threaded cases.
97+ */
98+ - (void )saveRequests : (NSMutableArray *)requests
99+ {
100+ if (requests.count > MAX_STORED_API_CALLS) {
101+ NSRange range = NSMakeRange (requests.count - MAX_STORED_API_CALLS, MAX_STORED_API_CALLS);
102+ requests = [[requests subarrayWithRange: range] mutableCopy ];
103+ }
104+
105+ NSError *error = nil ;
106+ NSData *requestData = [NSPropertyListSerialization dataWithPropertyList: requests
107+ format: NSPropertyListBinaryFormat_v1_0
108+ options: 0
109+ error: &error];
110+ if (requestData) {
111+ [requestData writeToFile: [self documentsFilePath ] atomically: YES ];
112+ LPLog (LPDebug, @" Saved %lu requests" , (unsigned long ) requests.count );
113+ } else {
114+ [[NSFileManager defaultManager ] removeItemAtPath: [self documentsFilePath ] error: &error];
115+ if (error) {
116+ LPLog (LPDebug, @" Error in saving requests: %@ " , error);
117+ }
118+ }
119+ }
83120
84- return requests;
121+ /* *
122+ * Load requests from the plist in documents directory.
123+ * Make sure to wrap this call with synchronize to support multi-threaded cases.
124+ */
125+ - (NSMutableArray *)loadRequests
126+ {
127+ @synchronized (self) {
128+ NSData *requestData = [NSData dataWithContentsOfFile: self .documentsFilePath];
129+ if (requestData) {
130+ NSError *error = nil ;
131+ NSMutableArray *requests = [NSPropertyListSerialization
132+ propertyListWithData: requestData
133+ options: NSPropertyListMutableContainers
134+ format: NULL error: &error];
135+ if (error) {
136+ LPLog (LPDebug, @" Error in loading requets: %@ " , error);
137+ } else {
138+ LPLog (LPDebug, @" Loaded %lu requests" , (unsigned long ) requests.count );
139+ }
140+
141+ return requests;
142+ }
143+ }
144+
145+ return [NSMutableArray new ];
85146}
86147
87148/* *
@@ -104,42 +165,11 @@ - (NSString *)documentsFilePath
104165 [NSString stringWithFormat: @" _lprequests-%@ " , LeanplumRequest.appId]];
105166}
106167
107- - (void )saveRequests
108- {
109- NSArray *requestsCopy;
110- @synchronized (self) {
111- requestsCopy = [_requests copy ];
112- }
113- if (requestsCopy.count > MAX_STORED_API_CALLS) {
114- NSRange range = NSMakeRange (requestsCopy.count - MAX_STORED_API_CALLS,
115- MAX_STORED_API_CALLS);
116- requestsCopy = [[requestsCopy subarrayWithRange: range] mutableCopy ];
117- }
118-
119- NSError *error = nil ;
120- NSData *requestData = [NSPropertyListSerialization dataWithPropertyList: requestsCopy
121- format: NSPropertyListBinaryFormat_v1_0 options: 0 error: &error];
122- if (requestData) {
123- [requestData writeToFile: [self documentsFilePath ] atomically: YES ];
124- } else {
125- [[NSFileManager defaultManager ] removeItemAtPath: [self documentsFilePath ] error: &error];
126- }
127-
128- LPLog (LPDebug, @" Saved %lu requests" , (unsigned long ) requestsCopy.count );
129- }
130-
131- + (LPRequestStorage *)sharedStorage
132- {
133- static LPRequestStorage *_sharedStorage = nil ;
134- static dispatch_once_t sharedStorageToken;
135- dispatch_once (&sharedStorageToken, ^{
136- _sharedStorage = [[self alloc ] init ];
137- });
138- return _sharedStorage;
139- }
140-
141- // For compatibility with older SDKs.
142- // TODO: Remove in April 2015.
168+ /* *
169+ * Returns the item key for requests data that is used in NSUserDefault.
170+ * This is here to be compatible with the older SDKS.
171+ * Safe to remove from April 2015.
172+ */
143173+ (NSString *)itemKeyForIndex : (NSUInteger )index
144174{
145175 return [NSString stringWithFormat: LEANPLUM_DEFAULTS_ITEM_KEY, index];
@@ -148,15 +178,17 @@ + (NSString *)itemKeyForIndex:(NSUInteger)index
148178- (void )pushRequest : (NSDictionary *)requestData
149179{
150180 @synchronized (self) {
151- [_requests addObject: requestData];
181+ NSMutableArray *requests = [self loadRequests ];
182+ [requests addObject: requestData];
183+ [self saveRequests: requests];
152184 }
153185}
154186
155187- (NSArray *)popAllRequests
156188{
157- NSArray *result = _requests ;
189+ NSMutableArray *requests ;
158190 @synchronized (self) {
159- _requests = [NSMutableArray array ];
191+ requests = [self loadRequests ];
160192 _lastSentTime = [NSDate timeIntervalSinceReferenceDate ];
161193
162194 NSError *error;
@@ -168,21 +200,9 @@ - (NSArray *)popAllRequests
168200 LPLog (LPDebug, @" Deleted stored requests." );
169201 }
170202 }
171-
172- // For compatibility with older SDKs.
173- // TODO: Remove in April 2015.
174- NSInteger count = [_defaults integerForKey: LEANPLUM_DEFAULTS_COUNT_KEY];
175- if (count > 0 ) {
176- [_defaults removeObjectForKey: LEANPLUM_DEFAULTS_COUNT_KEY];
177- for (NSInteger i = 0 ; i < count; i++) {
178- NSString * itemKey = [LPRequestStorage itemKeyForIndex: i];
179- [_defaults removeObjectForKey: itemKey];
180- }
181- [_defaults synchronize ];
182- }
183-
184203 }
185- return result;
204+ NSLog (@" pop: %@ " , requests);
205+ return requests;
186206}
187207
188208@end
0 commit comments