2013-04-09 43 views
-1

我有这种模式在我的iPhone应用程序之一的其他方法:的iOS:方法不等待调用完成

// 
// CatapultAccount.m 
// Catapult 
// 
// Created by Aziz Light on 4/9/13. 
// Copyright (c) 2013 Catapult Technology Ltd. All rights reserved. 
// 

#import "CatapultAccount.h" 

@interface CatapultAccount() 

- (BOOL)createAccountsTable; 

- (BOOL)accountWithNameIsAlreadyAdded:(NSString *)accountName; 

- (NSDictionary *)getAccountLogosForClient:(NSDictionary *)client; 

- (NSString *)getAccountLogoFromURL:(NSURL *)url; 

- (NSString *)saveImage:(UIImage *)image 
      withFileName:(NSString *)imageName 
       ofType:(NSString *)extension 
      inDirectory:(NSString *)directoryPath; 

@end 

@implementation CatapultAccount 

- (BOOL)createAccountWithAccountID:(NSString *)accountID 
{ 
    __block BOOL operationSuccessfull; 

    NXOAuth2Account *account = [[NXOAuth2AccountStore sharedStore] accountWithIdentifier:accountID]; 

    if (account == nil) { 
     operationSuccessfull = NO; 
    } else { 
     if ([self openDatabaseConnection]) { 
      if ([self createAccountsTable]) { 

       [NXOAuth2Request performMethod:@"GET" 
            onResource:[NSURL URLWithString:[NSString stringWithFormat:@"%@/users/me", kCatapultHost]] 
           usingParameters:nil 
            withAccount:account 
          sendProgressHandler:nil 
           responseHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) { 
            if (error != nil) { 
             operationSuccessfull = NO; 
#if DEBUG 
             NSLog(@"ERROR: %@", error); 
#endif 
             _lastError = error; 
            } else { 
             NSError *jsonError; 

             NSDictionary *serializedResponse = [NSJSONSerialization JSONObjectWithData:responseData 
                              options:kNilOptions 
                              error:&jsonError]; 

             if (jsonError != nil) { 
              operationSuccessfull = NO; 
#if DEBUG 
              NSLog(@"ERROR: %@", jsonError); 
#endif 
              _lastError = jsonError; 
             } else { 
              NSDictionary *user = [serializedResponse objectForKey:@"user"]; 
              NSDictionary *client = [serializedResponse objectForKey:@"client"]; 

              NSString *forename = [user objectForKey:@"forename"]; 
              NSString *surname  = [user objectForKey:@"surname"]; 
              NSString *accountName = [client objectForKey:@"account_name"]; 
              NSString *clientName = [client objectForKey:@"client_name"]; 

              if ([self accountWithNameIsAlreadyAdded:accountName]) { 
               operationSuccessfull = NO; 

               _lastError = [NSError errorWithDomain:kCatapultAccountErrorDomain 
                       code:kCatapultDuplicateAccountErrorCode 
                      userInfo:@{@"message": @"You have already added this account"}]; 

#if DEBUG 
               NSLog(@"ERROR: %@", _lastError); 
#endif 
              } else { 
               NSDictionary *logos = [self getAccountLogosForClient:client]; 

               operationSuccessfull = [self.db executeUpdate:@"insert into accounts(account_id, forename, surname, account_name, client_name, smallest_logo, thumb_logo) values(?,?,?,?,?,?,?)", 
                     accountID, forename, surname, accountName, clientName, logos[@"smallest_logo"], logos[@"thumb_logo"]]; 
              } 
             } 
            } 
           }]; 

      } else { 
       operationSuccessfull = NO; 

       _lastError = [NSError errorWithDomain:kCatapultDatabaseErrorDomain 
               code:kCatapultUnableToCreateTableErrorCode 
              userInfo:@{@"message": @"Unable to create the accounts table"}]; 

#if DEBUG 
       NSLog(@"ERROR: %@", _lastError); 
#endif 
      } 

      [self closeDatabaseConnection]; 
     } else { 
      operationSuccessfull = NO; 

      _lastError = [NSError errorWithDomain:kCatapultDatabaseErrorDomain 
              code:kCatapultUnableToOpenDatabaseConnectionErrorCode 
             userInfo:@{@"message": @"Unable to open database connection"}]; 

#if DEBUG 
      NSLog(@"ERROR: %@", _lastError); 
#endif 
     } 
    } 

    return operationSuccessfull; 
} 

- (BOOL)createAccountsTable 
{ 
    // Accounts table schema 
    // id integer primary key autoincrement 
    // account_id varchar(36) not null - unique 
    // forename varchar(255) not null 
    // surname varchar(255) not null 
    // account_name varchar(255) not null - unique 
    // client_name varchar(255) not null 
    // smallest_account_logo text 
    // thumb_account_logo text 

    BOOL tableCreationWasSuccessfull = [self.db executeUpdate:@"create table if not exists accounts(id integer primary key autoincrement, account_id varchar(36) not null, forename varchar(255) not null, surname varchar(255) not null, account_name varchar(255) not null, client_name varchar(255) not null, smallest_logo text, thumb_logo text, unique(account_id, account_name) on conflict abort)"]; 

    if (tableCreationWasSuccessfull) { 
     _lastError = nil; 
    } else { 
     _lastError = [self.db lastError]; 
#if DEBUG 
     NSLog(@"Failed to create users table: %@", _lastError); 
#endif 
    } 

    return tableCreationWasSuccessfull; 
} 

- (BOOL)accountWithNameIsAlreadyAdded:(NSString *)accountName 
{ 
    FMResultSet *account = [self.db executeQuery:@"select count(*) from accounts"]; 
    return [account next]; 
} 

- (NSDictionary *)getAccountLogosForClient:(NSDictionary *)client 
{ 
    NSString *smallestLogoURLString = [[[client objectForKey:@"logo"] objectForKey:@"smallest"] objectForKey:@"url"]; 
    NSString *smallestLogoPath = [self getAccountLogoFromURL:[NSURL URLWithString:smallestLogoURLString]]; 

    NSString *thumbLogoURLString = [[[client objectForKey:@"logo"] objectForKey:@"thumb"] objectForKey:@"url"]; 
    NSString *thumbLogoPath = [self getAccountLogoFromURL:[NSURL URLWithString:thumbLogoURLString]]; 

    return @{@"smallest_logo": smallestLogoPath, @"thumb_logo": thumbLogoPath}; 
} 

- (NSString *)getAccountLogoFromURL:(NSURL *)url 
{ 
    NSString *urlWithoutGETParams = [[[url absoluteString] componentsSeparatedByString:@"?"] objectAtIndex:0]; 
    NSString *lastSegmentOfURL = [[urlWithoutGETParams componentsSeparatedByString:@"/"] lastObject]; 
    NSString *logoName = [[lastSegmentOfURL componentsSeparatedByString:@"."] objectAtIndex:0]; 
    NSString *logoExtension = [[lastSegmentOfURL componentsSeparatedByString:@"."] lastObject]; 

    NSString * documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 

    NSString *logoPath = [documentsDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", logoName, logoExtension]]; 

    BOOL logoExists = [[NSFileManager defaultManager] fileExistsAtPath:logoPath]; 

    if (logoExists) { 
     return logoPath; 
    } else { 
     NSData *data = [NSData dataWithContentsOfURL:url]; 

     UIImage *logo = [UIImage imageWithData:data]; 

     logoPath = [self saveImage:logo withFileName:logoName ofType:logoExtension inDirectory:documentsDirectoryPath]; 

     return (logoPath == nil) ? nil : logoPath; 
    } 
} 

- (NSString *)saveImage:(UIImage *)image 
      withFileName:(NSString *)imageName 
       ofType:(NSString *)extension 
      inDirectory:(NSString *)directoryPath 
{ 
    NSData *imageRepresentation; 

    if ([[extension lowercaseString] isEqualToString:@"png"] || [[extension lowercaseString] isEqualToString:@"gif"]) { 
     imageRepresentation = UIImagePNGRepresentation(image); 
    } else if ([[extension lowercaseString] isEqualToString:@"jpg"] || [[extension lowercaseString] isEqualToString:@"jpeg"]) { 
     imageRepresentation = UIImageJPEGRepresentation(image, 1.0); 
    } else { 
#if DEBUG 
     NSLog(@"Image Save Failed\nExtension: (%@) is not recognized, use (PNG/JPG/GIF)", extension); 
#endif 
     return nil; 
    } 

    NSString *imagePath = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, extension]]; 

    NSError *error; 
    BOOL imageDidSave = [imageRepresentation writeToFile:imagePath 
               options:NSAtomicWrite 
                error:&error]; 

    if (error != nil) { 
#if DEBUG 
     NSLog(@"Error saving the file: %@", error); 
#endif 
    } 

    return (imageDidSave) ? imagePath : nil; 
} 

@end 

而且这种方法在我的视图控制器之一:

- (void)createAccount:(NSNotification *)notification 
{ 
    NXOAuth2Account *account = [notification.userInfo objectForKey:@"NXOAuth2AccountStoreNewAccountUserInfoKey"]; 

    if ([_accountModel createAccountWithAccountID:account.identifier]) { 
     // Do something 
     NSLog(@"Yay"); 
    } else { 
     // Delete the newly created account 
     [[NXOAuth2AccountStore sharedStore] removeAccount:account]; 

     UIAlertView *errorMessage = [[UIAlertView alloc] initWithTitle:@"Account Error" 
                   message:@"Unable to add new account" 
                   delegate:nil 
                cancelButtonTitle:@"OK" 
                otherButtonTitles:nil]; 

     [errorMessage show]; 
    } 

    [self dismissViewControllerAnimated:YES completion:nil]; 
} 

问题在于,根据我的(天真的)观察,在模型中使用数据库的大多数方法执行得太慢,并且createAccountWithAccountID:方法不会等待它调用完成的方法。的,其结果是,记录不会被保存到数据库,但由于某些原因,createAccountWithAccountID方法返回YES ...这里是说明我的意思日志:

2013-04-09 20:07:46.261 Catapult[21004:c07] Yay 
2013-04-09 20:07:46.276 Catapult[21004:c07] The FMDatabase <FMDatabase: 0x7288300> is not open. 
2013-04-09 20:07:46.606 Catapult[21004:c07] The FMDatabase <FMDatabase: 0x7288300> is not open. 

记录不会被保存到数据库中因为数据库连接太快......

有谁知道我该如何解决我的问题吗?

+0

请记住,您使用的是非Apple API,因此大多数人都没有听说过它。你必须检查NXOAuth2Request的文档以查看它的功能 - 你不能指望其他人为你做这件事。 – 2013-04-09 19:37:25

回答

1

大多数使用完成块的方法是异步执行的。该方法将立即返回,并且该请求会在请求实际完成时执行。您需要在代码中相应处理它。发送请求后,请勿释放任何内容,但请执行取决于响应处理程序块结果的任何内容,然后释放它。

+1

感谢您的评论。遵循您的建议和IRC人员的建议,我在'createAccountWithAccountID:'方法中添加了一个完成处理程序,并进行了一些其他重构,并解决了我的问题。 – 2013-04-09 20:30:08