Skip to content

Commit bb6f5fd

Browse files
author
Alexis Oyama
committed
fix(request): Write requests to file instead of keeping in memory
1 parent 5839c2c commit bb6f5fd

File tree

3 files changed

+107
-87
lines changed

3 files changed

+107
-87
lines changed

Leanplum-SDK/Classes/LPRequestStorage.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
@interface LPRequestStorage : NSObject {
2828
@private
2929
NSTimeInterval _lastSentTime;
30-
NSMutableArray *_requests;
3130
NSUserDefaults *_defaults;
3231
}
3332

Leanplum-SDK/Classes/LPRequestStorage.m

Lines changed: 106 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Leanplum-SDK/Classes/Leanplum.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,7 @@ + (void)startWithUserId:(NSString *)userId
886886
state.hasStarted = YES;
887887
state.startSuccessful = YES;
888888
NSDictionary *response = [LPResponse getLastResponse:json];
889+
NSLog(@"RESPONSE: %@", response);
889890
NSDictionary *values = response[LP_KEY_VARS];
890891
NSString *token = response[LP_KEY_TOKEN];
891892
NSDictionary *messages = response[LP_KEY_MESSAGES];

0 commit comments

Comments
 (0)