简体   繁体   中英

Best way to store data for an iPhone calendaring app

I am working on an iPhone app. It is a Enterprise calendaring app for my agency. We have a RESTful API backend connected to a web application where the appointments are entered. The appointments for an individual are to show up on that user's iPhone. Data is sent by XML. There are only 3 or 4 appointments per day and less than 10 fields per record, so not a lot of data is transferred at a time (just the selected day's information).

I tried to design this with an array on the iPhone for the parsed data, but the security checking on the web server makes the application time out when loading the data, and I didn't handle the asynchronous processing well.

Now I'm wondering if I'm even approaching the problem correctly. Would it be better to use Core Data to store the appointments and then work to update the Core Data store in the background? I know I need to update the data outside of the loading the table process. I'm just at a loss for the best way to approach this.

I have looked through the site for information as to how to approach this. I have tried looking in books. Any help would be appreciated.

Security.h

typedef void (^touchIDComplete)(BOOL);
typedef void (^fileExists)(BOOL);
typedef void (^sessionVerify)(BOOL);
typedef void (^parsingData)(BOOL);
typedef void (^touchIDSuccess)(BOOL);
typedef void (^sessionRetrieved)(BOOL);
typedef void (^touchIDComplete)(BOOL);
typedef void (^sessionReading)(BOOL);
typedef void (^fillArray)(BOOL);
typedef void (^getTheData)(NSData *myData, NSError *error);
typedef void (^gettingESNBlock)(NSString *myESN, NSString *newSession, BOOL success, NSError *error);
typedef void (^checkingESNBlock)(NSString *myESN, NSString *sessionInfo, BOOL success, NSError *error);


@interface Security : NSObject

@property (strong, nonatomic) NSArray *types;
@property (strong, nonatomic) NSArray *esn;
@property (strong, nonatomic) NSString *idfv;
@property (strong, nonatomic) NSData *parseData;
@property (strong, nonatomic) NSString *sessionDetail;
@property (strong, nonatomic) NSString *loginFinished;
@property (strong, nonatomic) NSMutableURLRequest *request;
@property (atomic) NSString *passESN;

- (void)waitForData:(sessionVerify)compblock;
- (void)waitForFile:(fileExists)compblock;
- (void)waitForESN:(parsingData)compblock;
- (void)findESN:(gettingESNBlock)callback;
- (void)checkThumb:(touchIDSuccess)compblock;
- (void)readIt:(sessionRetrieved)compblock;
- (void)readNewSession:(sessionReading)compblock;
- (void)doTheWork:(NSString *)theESN withSession:(NSString *)newSession withSuccess:(BOOL)success error:(NSError *)error;
- (void)checkESN:(checkingESNBlock)callback;
- (void)checkTheSession:(NSString *)oldESN withSession:(NSString *)oldSession withSuccess:(BOOL)success error:(NSError *)error;
- (void)fillAppointmentData:(fillArray)compblock;
- (void)gettingData:(getTheData)compblock;

@end

Security.m

@implementation Security

void(^getESNForCallback)(NSString *myESN, NSString *newSession, BOOL success, NSError *error);
void(^checkESNWithCallback)(NSString *myESN, NSString *oldSession, BOOL success, NSError *error);

- (void)waitForFile:(fileExists) compblock {

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [directoryPaths objectAtIndex:0];
    NSString *fullPath = [documentsDirectoryPath stringByAppendingString:@"/session.txt"];
    compblock([fileManager fileExistsAtPath:fullPath]);
}

- (void) waitForData:(sessionVerify) compblock {
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:self.request
                                        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                                            if (error) {
                                                return;
                                            }

                                            if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                                NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];

                                                if (statusCode != 200) {
                                                    if (statusCode == 401) {
                                                        // Insert process for thumbprint and session cookie pull
                                                        NSFileManager *fileManagerThree = [NSFileManager defaultManager];
                                                        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
                                                        NSString *sessionPath = [documentsPath stringByAppendingPathComponent:@"session.txt"];
                                                        NSError *error;
                                                        BOOL success = [fileManagerThree removeItemAtPath:sessionPath error:&error];
                                                        if (success) {
                                                        } else {
                                                        }
                                                    } else {
                                                        return;
                                                    }
                                                }
                                            }
                                            self.parseData = data;
                                            compblock (YES);
                                        }];
    [task resume];
}

- (void)waitForESN:(parsingData) compblock {
    ParseTypeXML *myParser = [[ParseTypeXML alloc] initWithData:self.parseData];
    VariableStore *globals = [VariableStore sharedInstance];
    if ([myParser.esn count] == 0) {
        globals.user_esn = @"Error";
        compblock(YES);
    } else {
        globals.user_esn = myParser.esn[0];
        compblock(YES);
    }
}

- (void)findESN:(gettingESNBlock)callback {
    getESNForCallback = callback;
    VariableStore *globals = [VariableStore sharedInstance];
    [self doTheWork:globals.user_esn withSession:globals.sessionInfo withSuccess:YES error:nil];
}

- (void)doTheWork:(NSString *)theESN withSession:(NSString *)newSession withSuccess:(BOOL)success error:(NSError *)error {
    [self checkThumb:^(BOOL finished) {
        if(finished) {
            [self readIt:^(BOOL newFile) {
                if (newFile) {
                    [self readNewSession:^(BOOL seen) {
                        if (seen) {
                            VariableStore *globals = [VariableStore sharedInstance];
                            NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                                        @"ollie/", NSHTTPCookieDomain,
                                                        @"\\", NSHTTPCookiePath,
                                                        @"Cookie", NSHTTPCookieName,
                                                        globals.sessionInfo, NSHTTPCookieValue,
                                                        nil];
                            NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
                            NSArray *cookieArray = [NSArray arrayWithObject:cookie];
                            NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];

                            NSMutableString *url = [[NSMutableString alloc] initWithString:@"https://company.com/file.php"];

                            NSURL *urlNew = [NSURL URLWithString:url];
                            self.request = [NSMutableURLRequest requestWithURL:urlNew];
                            [self.request setHTTPMethod:@"GET"];
                            [self.request setAllHTTPHeaderFields:headers];

                            [self waitForData:^(BOOL dataReceived) {
                                if (dataReceived) {
                                    [self waitForESN:^(BOOL esnFound) {
                                        if (esnFound) {
                                            VariableStore *globals = [VariableStore sharedInstance];
                                            getESNForCallback(globals.user_esn, globals.sessionInfo, success, error);
                                        }
                                    }];
                                }
                            }];
                        }
                    }];
                }
            }];
        }
    }];
}

- (void)checkThumb:(touchIDSuccess)compblock {
    LAContext *context = [[LAContext alloc] init];
    NSError *error = nil;

    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
        // Authenticate User
        [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
            localizedReason:@"You need to log in."
                      reply:^(BOOL success, NSError * _Nullable error) {
                          if (success) {
                              NSLog(@"success");
                              compblock(YES);
                          } else {
                              switch (error.code) {
                                  case LAErrorAuthenticationFailed:
                                      break;
                                  case LAErrorUserCancel:
                                      break;
                                  case LAErrorUserFallback:
                                      break;

                                  default:
                                      break;
                              }
                          }
                      }];
    }
}

- (void)readIt:(sessionRetrieved)compblock {
    NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    NSString *url = @"https://company.com/specialstring.php";

    NSMutableString *postText = [[NSMutableString alloc] init];

    [postText appendString:idfv];

    NSString *postBody = [NSString stringWithString:postText];

    XMLPostSecurity *postAction = [[XMLPostSecurity alloc] init];
    VariableStore *globals = [VariableStore sharedInstance];
    globals.sessionInfo = [postAction sendPostRequestToUrl:url withBody:postBody];

    FileSaving *saver = [[FileSaving alloc] init];

    [saver saveSession:globals.sessionInfo];
    compblock(YES);
}

-(void)readNewSession:(sessionReading)compblock {
    NSFileManager *fileManagerTwo;
    NSData *dataBuffer;
    fileManagerTwo = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingString:@"/session.txt"];

    dataBuffer = [fileManagerTwo contentsAtPath:filePath];
    VariableStore *globals = [VariableStore sharedInstance];
    globals.sessionInfo = [[NSString alloc] initWithData:dataBuffer encoding:(NSASCIIStringEncoding)];
    compblock(YES);
}

- (void)checkESN:(checkingESNBlock)callback {
    checkESNWithCallback = callback;
    VariableStore *globals = [VariableStore sharedInstance];
    [self checkTheSession:globals.user_esn withSession:globals.sessionInfo withSuccess:YES error:nil];
}

- (void)checkTheSession:(NSString *)theESN withSession:(NSString *)oldSession withSuccess:(BOOL)success error:(NSError *)error {
    [self readNewSession:^(BOOL seen) {
        if (seen) {
            VariableStore *globals = [VariableStore sharedInstance];
            NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                            @"ollie/", NSHTTPCookieDomain,
                                            @"\\", NSHTTPCookiePath,
                                            @"Cookie", NSHTTPCookieName,
                                            globals.sessionInfo, NSHTTPCookieValue,
                                            nil];
            NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
            NSArray *cookieArray = [NSArray arrayWithObject:cookie];
            NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];

            NSMutableString *url = [[NSMutableString alloc] initWithString:@"https://company.com/file.php"];

            NSURL *urlNew = [NSURL URLWithString:url];
            self.request = [NSMutableURLRequest requestWithURL:urlNew];
            [self.request setHTTPMethod:@"GET"];
            [self.request setAllHTTPHeaderFields:headers];

            [self waitForData:^(BOOL dataReceived) {
                if (dataReceived) {
                    [self waitForESN:^(BOOL esnFound) {
                        if (esnFound) {
                            VariableStore *globals = [VariableStore sharedInstance];
                            checkESNWithCallback(globals.user_esn, globals.sessionInfo, success, error);
                        }
                    }];
                }
            }];
        }
    }];
}

- (void)fillAppointmentData:(fillArray)compblock {

    VariableStore *globals = [VariableStore sharedInstance];

    NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                  @"ollie/", NSHTTPCookieDomain,
                                  @"\\", NSHTTPCookiePath,
                                  @"Cookie", NSHTTPCookieName,
                                  globals.sessionInfo, NSHTTPCookieValue,
                                  nil];
    NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
    NSArray *cookieArray = [NSArray arrayWithObject:cookie];
    NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];

    NSMutableString *url = [[NSMutableString alloc] initWithString:@"https://company.com/file2.php?adb="];

    [url appendString:globals.chosenDate];
    [url appendString:@"&esn="];
    [url appendString:globals.user_esn];

    NSURL *urlNew = [NSURL URLWithString:url];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlNew];
    [request setHTTPMethod:@"GET"];
    [request setAllHTTPHeaderFields:headers];

    [self gettingData:^(NSData *myData, NSError *error) {
        if (myData != nil) {
            ParseXML *myParser = [[ParseXML alloc] initWithData:myData];

            [globals.appointmentData removeAllObjects];

            [globals.appointmentData addObjectsFromArray:myParser.items];
        }
    }];
}

- (void) gettingData:(getTheData) compblock {
    VariableStore *globals = [VariableStore sharedInstance];
    globals.got401 = nil;
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:self.request
                                        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                                            if (error) {
                                                return;
                                            }

                                            if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                                NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];

                                                if (statusCode != 200) {
                                                    if (statusCode == 401) {
                                                        // Insert process for thumbprint and session cookie pull
                                                        NSFileManager *fileManagerThree = [NSFileManager defaultManager];
                                                        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
                                                        NSString *sessionPath = [documentsPath stringByAppendingPathComponent:@"session.txt"];
                                                        NSError *error;
                                                        BOOL success = [fileManagerThree removeItemAtPath:sessionPath error:&error];
                                                        if (success) {
                                                        } else {
                                                        }
                                                        globals.got401 = @"Error";
                                                    } else {
                                                        return;
                                                    }
                                                }
                                            }
                                            self.parseData = data;
                                        }];
    [task resume];
}

@end

If you only have 3 or 4 appointments worth of data stored locally then the answer is "whatever is easiest for you." It really doesn't matter. You could convert the data to morse code and save dots and dashes and then read that and it would still be small and fast enough.

You can save the data to a plist, serialize it using NSCoding, save it as a SQLite database, or even write the XML and convert it back to an array on reading it (although the XML option is probably the slowest/least efficient.)

Core Data is very powerful (and very cool) but it also has a very steep learning curve. I would not recommend it until you are comfortable working with iOS.

If your application is timing out then there is probably something else wrong. Edit your question to show the code for the problem area and perhaps we can help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM