私はView Controllerからクラスメソッドを呼び出す必要があり、それを行う必要がありますが、クラスメソッドが完了した後にのみいくつかのアクションを実行します。
(必要なのは完了ブロックだと思いますが、間違っている場合は修正してください。)
状況は次のとおりです。
アプリのバックエンドにParse.comを使用しています。ユーザーがアカウントにサインアップすると、名前、会社、その他の情報をポップアップに入力し、[送信]をクリックします。送信ボタンは、PFUserオブジェクトと会社名を取り、いくつかのデータベースオブジェクトを作成するクラスメソッド(以下に表示)にリンクされています。関数が完了すると、デリゲートを使用してポップアップが閉じられます。
問題は、これらのオブジェクトを特定の順序で作成する必要があることです。これらのオブジェクトは、存在する他のobjectIdに依存しているためです。問題は、ポップアップが表示されないようにするデリゲートメソッドが、スタックの次のサブミットであるため、[送信]をクリックした直後に呼び出されることです。
Parseオブジェクトを保存するとき、次のようなメソッドを呼び出します(これは、私が書きたいと思っているもので、私の問題を解決すると思います)。
[someParseObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// Code here runs AFTER the method completes.
// This also happens on another thread which
// I'd like to implement as well.
}];
だから、私は次のようなことをする方法を理解するために必要なもの:(ブロックに関係するすべてが完全に間違っていると確信しています)
SignUpViewController.m
myUserOrg *userOrg = [myUserOrg object]; // myUserOrg = Custom PFObject Subclass
// My method that takes in a user object and a string, creates
// the database objects in order.
[userOrg registerNewUserOrgWithUser:(PFUser*) andCompanyName:(NSString*) companyName withBlock(somethingHere)block {
if(error) {
NSLog(@"Unable to create org!");
} else {
NSLog(@"Created Org!");
[self.delegate dismissSignupView];
}
追加情報や説明が必要な場合はお知らせください。
前もって感謝します!
---------編集1 ----------
申し分なく、かなりの時間の後に、これが私が思いついたものです。実装全体をより単純化し、API呼び出しをはるかに少なくすることができますが、それでも動作します。他にもいくつかの明白な問題がありますが、最初のステップです。
メソッド呼び出し:
[testOrg registerNewUserOrgWithUser:currentUser
creatingOrgContactWithName:@"MyBigHappy Corp."
withBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(@"Not working");
} else {
NSLog(@"Working!");
}
}];
メソッドの実装:
@implementation MYUserOrg
@dynamic orgContact;
@dynamic orgDisplayName;
@dynamic members;
@dynamic contacts;
+ (NSString *)parseClassName {
return @"MYUserOrg";
}
dispatch_queue_t NewUserOrgRegistrationQueue;
-(void)registerNewUserOrgWithUser:(MYUser*)user
creatingOrgContactWithName:(NSString*) orgContactName
withBlock:(MYBooleanResultBlock) block {
NewUserOrgRegistrationQueue = dispatch_queue_create("com.myapp.initialOrgCreationQueue", NULL);
dispatch_async(NewUserOrgRegistrationQueue, ^{
NSMutableArray *errors = [[NSMutableArray alloc] init];
// Initial org save to generate objectId
NSError *orgSaveError = nil;
[self save:&orgSaveError];
if (orgSaveError) {
[errors addObject:@"Initial Org save Failed"];
}
// Create and Relate Org Contact
NSError *saveOrgContactError = nil;
MYontact *orgContact = [MYContact object];
[orgContact setContactType:MYContactTypeUserOrganization];
[orgContact setDisplayName:orgContactName];
[orgContact setParentOrg:self];
[orgContact save:&saveOrgContactError];
if (saveOrgContactError) {
[errors addObject:@"Saving Org Contact Failed"];
} else {
// If Org contact saved, set it;
[self setOrgContact:orgContact];
}
// Create AMD Relate User Contact
NSError *saveUserContactError = nil;
MYContact *userContact = [MYContact object];
[userContact setFirstName:user.firstName];
[userContact setLastName:user.lastName];
[userContact setContactType:MYcontactTypeUser];
[userContact setParentOrg:self];
[userContact save:&saveUserContactError];
if (saveUserContactError) {
[errors addObject:@"Saving user contact failed"];
}
NSError *saveUserError = nil;
[user setParentOrg:self];
[user setUserContact:userContact];
[user save:&saveUserError];
if (saveUserError) {
[errors addObject:@"Saving User failed"];
}
// Return if block succeeded and any errors.
NSError *error = nil;
BOOL succeeded;
if (errors.count > 0) {
NSDictionary *userInfo = @{@"error" : errors};
errors = [NSError errorWithDomain:@"MyAppErrorDomain"
code:1
userInfo:userInfo];
succeeded = NO;
} else {
succeeded = YES;
}
block(succeeded, error);
});
}
@end
ブロックを書きたいときはいつもこれを使います:
または以下の不敬なバージョン:
http://goshdarnblocksyntax.com/
Swiftの場合:
https://web.archive.org/web/20180527074325/http://fuckingswiftblocksyntax.com:80/
振った後にサイコロの値を返すクラスのcompletionBlockを作成しました。
ReturnType(.h
上の@interface
宣言)でtypedefを定義します
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
ブロックの@property
を定義します(.h
)
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
finishBlock
(.h
)でメソッドを定義します
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
前に定義したメソッドを.m
ファイルに挿入し、finishBlock
を前に定義した@property
にコミットします
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
completionBlock
をトリガーするには、定義済みのvariableTypeを渡します(completionBlock
が存在するかどうかを確認することを忘れないでください)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
http://goshdarnblocksyntax.com/ に関して
ローカル変数として:
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
プロパティとして:
@property (nonatomic, copy) returnType (^blockName)(parameterTypes);
methodパラメーターとして:
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
メソッド呼び出しへの引数として:
[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];
typedefとして:
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};
ブロックをカスタムタイプとして定義します。
typedef void (^ButtonCompletionBlock)(int buttonIndex);
次に、それをメソッドの引数として使用します。
+ (SomeButtonView*)buttonViewWithTitle:(NSString *)title
cancelAction:(ButtonCompletionBlock)cancelBlock
completionAction:(ButtonCompletionBlock)completionBlock
これをコードで呼び出す場合、他のブロックとまったく同じです。
[SomeButtonView buttonViewWithTitle:@"Title"
cancelAction:^(int buttonIndex) {
NSLog(@"User cancelled");
}
completionAction:^(int buttonIndex) {
NSLog(@"User tapped index %i", buttonIndex);
}];
ブロックをトリガーするときが来たら、単にcompletionBlock()を呼び出します(completionBlockは、ブロックのローカルコピーの名前です)