ios 如何编写一个 Objective-C 完成块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21436831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to write an Objective-C Completion Block
提问by Andrew
I'm in a situation where need to call a class method from my view controller, have it do it's thing, but then perform some actions ONLY AFTER the class method has completed.
我处于一种需要从我的视图控制器调用类方法的情况,让它做它的事情,但是只有在类方法完成后才执行一些操作。
(I think what I need is a completion block, but please correct me if I'm wrong.)
(我想我需要的是一个完成块,但如果我错了,请纠正我。)
Here is the situation:
这是情况:
I'm using Parse.com for my apps back end. When a user signs up for an account, they enter their name, company and some other info in a popup then click submit. The submit button is linked to a class method (shown below) which takes their PFUser object, and company name and creates some database objects. After the function completes, the popup is dismissed using a delegate.
我将 Parse.com 用于我的应用程序后端。当用户注册一个帐户时,他们在弹出窗口中输入他们的姓名、公司和其他一些信息,然后单击提交。提交按钮链接到一个类方法(如下所示),该方法获取他们的 PFUser 对象和公司名称并创建一些数据库对象。函数完成后,使用委托关闭弹出窗口。
The issue is I need the creation of these objects to happen in a specific order because they depend on each others objectId's to exist. The problem is, the delegate method to dismiss the popup is called right away after clicking submit as it's the next on the stack.
问题是我需要以特定顺序创建这些对象,因为它们依赖于彼此的 objectId 的存在。问题是,在单击提交后立即调用解除弹出窗口的委托方法,因为它是堆栈中的下一个。
When saving a Parse object one calls a method that looks something like this: (This is kind of what I'm hoping to write and I think would solve my issue)
当保存 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.
}];
So, What I need to figure out how to do something like the following: (Everything having to do with the block is completely wrong I'm sure)
因此,我需要弄清楚如何执行以下操作:(我确定与块有关的一切都是完全错误的)
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];
}
Please let me know if you need additional information or clarification.
如果您需要其他信息或说明,请告诉我。
Thank you in advance!
先感谢您!
--------- EDIT ONE ----------
--------- 编辑一个 ----------
Alright, So several sizeable units of time later, this is what I've come up with. The whole implementation could be better simplified and make far fewer api calls but will work on that. Several other glaring issues with it as well but is a first step.
好的,在几个相当大的时间单位之后,这就是我想出的。整个实现可以更好地简化并减少 api 调用,但会继续努力。它还有其他几个明显的问题,但这只是第一步。
Method Call:
方法调用:
[testOrg registerNewUserOrgWithUser:currentUser
creatingOrgContactWithName:@"MyBigHappy Corp."
withBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(@"Not working");
} else {
NSLog(@"Working!");
}
}];
Method Implementation:
方法实现:
@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
回答by CW0007007
I always use this when I want to write a block:
当我想写一个块时,我总是使用它:
EDIT
编辑
If you are writing Swift then use this:
如果您正在编写 Swift,请使用以下命令:
http://fworingswiftblocksyntax.com
http://fworingswiftblocksyntax.com
If the above links are not opening because of the obscene language, use this one.
如果上述链接因淫秽语言而无法打开,请使用此链接。
回答by Alex Cio
I wrote a completionBlock for a class which will return the values of a dice after they have been shaked:
我为一个类编写了一个completionBlock,它会在摇动骰子后返回骰子的值:
Define typedef with returnType (
.h
above@interface
declaration)typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Define a
@property
for the block (.h
)@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
Define a method with
finishBlock
(.h
)- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Insert previous defined method in
.m
file and commitfinishBlock
to@property
defined before- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{ self.completeDiceRolling = finishBlock; }
To trigger
completionBlock
pass predefined variableType to it (Don't forget to check whether thecompletionBlock
exists)if( self.completeDiceRolling ){ self.completeDiceRolling(self.dieValue); }
用 returnType 定义 typedef(
.h
上面的@interface
声明)typedef void (^CompleteDiceRolling)(NSInteger diceValue);
@property
为块 (.h
)定义 a@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); }
回答by DURGESH
You define the block as a custom type:
您将块定义为自定义类型:
typedef void (^ButtonCompletionBlock)(int buttonIndex);
Then use it as an argument to a method:
然后将其用作方法的参数:
+ (SomeButtonView*)buttonViewWithTitle:(NSString *)title
cancelAction:(ButtonCompletionBlock)cancelBlock
completionAction:(ButtonCompletionBlock)completionBlock
When calling this in code it is just like any other block:
在代码中调用它时,它就像任何其他块一样:
[SomeButtonView buttonViewWithTitle:@"Title"
cancelAction:^(int buttonIndex) {
NSLog(@"User cancelled");
}
completionAction:^(int buttonIndex) {
NSLog(@"User tapped index %i", buttonIndex);
}];
If it comes time to trigger the block, simply call completionBlock() (where completionBlock is the name of your local copy of the block
如果需要触发块,只需调用 completionBlock()(其中 completionBlock 是块的本地副本的名称
回答by carmen_munich
Regarding to http://goshdarnblocksyntax.com/
关于http://goshdarnblocksyntax.com/
As a local variable:
作为局部变量:
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
As a property:
作为财产:
@property (nonatomic, copy) returnType (^blockName)(parameterTypes);
As a method parameter:
作为方法参数:
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
As an argument to a method call:
作为方法调用的参数:
[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];
As a typedef:
作为typedef:
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};