I use clang-format to format my code.
Everything works fine except for the block code, as you can see the code below, the failure block has indent 4 space ...
_loginOperation = [CheckTIMPreparation tim_CheckPreparationSuccess:^{
[weakSelf checkIsJoinGroup];
} failure:^(NSString *errorString) {
[weakSelf showloginingViewWithFail];
}];
after format:
_loginOperation = [CheckTIMPreparation tim_CheckPreparationSuccess:^{
[weakSelf checkIsJoinGroup];
}
failure:^(NSString *errorString) {
[weakSelf showloginingViewWithFail];
}];
How can I customize my clang-format config?
Here is my config:
BasedOnStyle: LLVM
IndentWidth: 4
BreakBeforeBraces: Attach
AllowShortIfStatementsOnASingleLine: true
IndentCaseLabels: true
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ColumnLimit: 0
AlignTrailingComments: true
SpaceAfterCStyleCast: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
It's four years later now, but possibly somebody would like to see an answer to this question anyway...
Just to be sure, your question title seems to ask how to prevent clang-format from modifying a block of code. If that's all you want, you can do that by putting // clang-format off and // clang-format on around that code. See the documentation for more details.
You don't mention what version of clang-format you're using, and unfortunately your code is formatted differently by different versions of clang-format. (I explored these versions using the configurator).
Version 3.5.2 gives:
_loginOperation = [CheckTIMPreparation tim_CheckPreparationSuccess:^{
[weakSelf checkIsJoinGroup];
} failure:^(NSString *errorString) { [weakSelf showloginingViewWithFail]; }];
Version 3.6.0 gives:
_loginOperation = [CheckTIMPreparation tim_CheckPreparationSuccess:^{
[weakSelf checkIsJoinGroup];
} failure:^(NSString *errorString) {
[weakSelf showloginingViewWithFail];
}];
Versions 3.7.0 through 6.0.1 give:
_loginOperation = [CheckTIMPreparation tim_CheckPreparationSuccess:^{
[weakSelf checkIsJoinGroup];
}
failure:^(NSString *errorString) {
[weakSelf showloginingViewWithFail];
}];
Version 7.0.1 through 10.0.0 give:
_loginOperation = [CheckTIMPreparation
tim_CheckPreparationSuccess:^{
[weakSelf checkIsJoinGroup];
}
failure:^(NSString *errorString) {
[weakSelf showloginingViewWithFail];
}];
So you were perhaps using something like version 6.0.0, and simply upgrading to a newer version of clang-format might give you formatting that you would like better.
In addition, you may also want to set the style option AllowShortBlocksOnASingleLine: true (see the documentation for details). For clang-format version 10.0.0, your code would then look like this:
_loginOperation = [CheckTIMPreparation
tim_CheckPreparationSuccess:^{ [weakSelf checkIsJoinGroup]; }
failure:^(NSString *errorString) { [weakSelf showloginingViewWithFail]; }];
Related
I did a login which is connected to a button in ReactiveCocoa. Even I tested this piece of code and it seems to work correctly, I am not sure if I do it right.
The login signal returns "next" on success and "error" in any other case. Since I don't want the Button to be unsubscribed on an error I use the catch function.
What I want: I want a timeout to fire after 2 seconds, if the loginSignal is not fired. Is this correctly done? Is it also done right the "reactive way"?
[[[[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside]
doNext:^(id x) {
[self disableUI];
}]
flattenMap:^(id value) {
return [[[[[self.login loginSignalWithUsername:self.usernameTextField.text
andPassword:self.passwordTextField.text]
catch:^RACSignal *(NSError *error) {
[self enableUI];
[self showAlertWithTitle:NSLocalizedString(#"ERROR_TITLE", #"Error")
message:NSLocalizedString(#"LOGIN_FAILURE", #"Login not successful.")];
return [RACSignal empty];
}]
deliverOn:[RACScheduler mainThreadScheduler]]
timeout:2.0 onScheduler:[RACScheduler mainThreadScheduler]]
catch:^RACSignal *(NSError *error) {
[self enableUI];
[self showAlertWithTitle:NSLocalizedString(#"TIMEOUT_TITLE", #"Timeout occured")
message:NSLocalizedString(#"REQUEST_NOT_POSSIBLE", #"Server request failed")];
return [RACSignal empty];
}];
}]
subscribeNext:^(id x) {
[self enableUI];
// Go to next page after login
}];
You should in my opinion use RACCommand which is a nice hub for binding signals to UI :
RACCommand* command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
return [[[self.login loginSignalWithUsername:self.username password:self.password]
doCompleted:^{
// move to next screen
}]
timeout:2.0 onScheduler:[RACScheduler mainThreadScheduler]];
}];
self.button.rac_command = command;
You can then handle any errors (login or timeout) using the command "errors" signal :
[[command errors] subscribeNext:^(NSError* err) {
// display error "err" to the user
}];
The signal will automatically disable the button while it is executing. If you need to disable other parts of your UI you can use the "executing" signal of the command.
[[command executing] subscribeNext:^(NSNumber* executing) {
if([executing boolValue]) {
[self disableUI];
} else {
[self enableUI];
}
}];
// bonus note: if your enableUI method took a BOOL you could lift it in one line :
[self rac_liftSelector:#selector(enableUI:) withSignals:[command executing], nil];
here is a blog article talking about RACCommands
I have started to explore the new XCTest APIs for asynchronous and performance testing. In isolation, the Apple examples from WWMC work well, but I have been unable to figure out how to combine them. The best I have been able to come up with is the following, but I receive the following error when it runs:
API violation - call made to wait without any expectations having been set.
XCTestExpectation *clsQueryReturnedExpectation = [self expectationWithDescription:#"clsQuery returned"];
PFCLSClient *theClient = [[PFCLSClient alloc] init];
[self measureMetrics:#[XCTPerformanceMetric_WallClockTime] automaticallyStartMeasuring:YES forBlock: ^{
[theClient getStructureOfType:clsImageTypeSVG ForID:idString success: ^(NSDictionary *structureInfo) {
[clsQueryReturnedExpectation fulfill];
} failure: ^(NSError *error) {
XCTFail();
[clsQueryReturnedExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler: ^(NSError *error) {
[self stopMeasuring];
}];
}];
Has anyone been able to accomplish something similar?
Thx
With some help from Apple, I have a solution. Silly oversight on my part as this is very easy to solve. To get to work, all you need to do is put the creating of the expectation object (clsQueryReturnedExpectation) inside the measureMetrics block so it is created afresh each time the performance test is run.
PFCLSClient *theClient = [[PFCLSClient alloc] init];
[self measureMetrics:#[XCTPerformanceMetric_WallClockTime] automaticallyStartMeasuring:YES forBlock: ^{
XCTestExpectation *clsQueryReturnedExpectation = [self expectationWithDescription:#"clsQuery returned"];
[theClient getStructureOfType:clsImageTypeSVG ForID:idString success: ^(NSDictionary *structureInfo) {
[clsQueryReturnedExpectation fulfill];
} failure: ^(NSError *error) {
XCTFail();
[clsQueryReturnedExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler: ^(NSError *error) {
[self stopMeasuring];
}];
}];
After looking at this link API mode error I corrected some code using STTwitter. This eradicated one error but made me notice a new CFNetwork error. Whenever I try to fetch statuses using either getHomeTimelineSinceID or getUserTimelinewithScreenName, the error "CFNetwork internal error (0xc01a:/SourceCache/CFNetwork/CFNetwork-695.1.5/Foundation/NSURLRequest.mm:798)" pops up in the debugger. After debugging I found the error pops right after [r Asynchronous] (line 272 of STTwitterAppOnly.m). I got to this spot by stepping into verifyCredentialsWithSuccessBlock.
The code I am currently using:
[twitter verifyCredentialsWithSuccessBlock:^(NSString *bearerToken) {
[twitter getHomeTimelineSinceID:nil
count:20
successBlock:^(NSArray *statuses) {
NSLog(#"-- statuses: %#", statuses);
self.twitterFeed = statuses;
[self.tableView reloadData];
} errorBlock:^(NSError *error) {
}];
And I have also tried:
[twitter getUserTimelineWithScreenName:#"Dandelion_2014"
successBlock:^(NSArray *statuses) {
self.twitterFeed = [NSMutableArray arrayWithArray:statuses];
[self.tableView reloadData];
} errorBlock:^(NSError *error) {
NSLog(#"%#", error.debugDescription);
}];
I'm not sure what is causing this error, does anybody have insight?
I think I found the issue.
iOS 8 raises a runtime warning when setting -[NSURLRequest HTTPMethod] to nil.
I updated STHTTPRequest and STTwitter.
Let me know if it works for you.
GCD and blocks are so nice and convenient. But when I fall in love with it, I found that something bad happened. Look at these codes below:
[self functionA:^(BOOL success) {
if (success) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[self functionB:^(NSError *error) {
if (error != nil) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self functionC:^(id result) {
if (result) {
[self functionD:^(BOOL success) {
if (success) {
[self DoSomething];
}
}];
}
}];
});
}
}];
});
}
}];
Crazy? Yes. I am in this trouble.
Did someone have any experience avoiding nested blocks like this?
Edited:
Thanks guys. Exactly, we have more elegant ways to do this. Such as:
Declare blocks beforehand
Make sub blocks as independent function
But what I expect is a general solution. Maybe like this:(Pseudo code below)
functionA.flat.success = [self functionB];
functionB.flat.isntnil = [self functionC];
functionB.flat.error = {};
functionC.flat.isntnil = [self functionD];
[flat call:functionA];
Well, I haven't bothered matching your cloud of closing braces, but here's a try by simply using return, which you can use freely inside blocks too and cuts the nesting a little:
[self functionA:^(BOOL success) {
if (!success)
return;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[self functionB:^(NSError *error) {
if (!error)
return;
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self functionC:^(id result) {
if (!result)
return;
[self functionD:^(BOOL success) {
if (!success)
return;
[self DoSomething];
}];
}];
});
}];
});
}];
Also, nobody forces you to write blocks inline, you can declare them as normal variables before and use them later. In fact, by declaring blocks before you are able to reuse them if your API is lenient towards its users and allows being called repeatedly even when no work has to be done:
- (void)foo:(Bar*)bar
{
// Prepare the success handler.
void (^successBlock)(Bar*) = ^(Bar *bar) {
[[NSNotificationCenter defaultCenter]
postNotificationName:#"barUpdated"
object:bar];
};
if (!bar.didAlreadyFetchStuff) {
[self wellYouBetterFetchSomething:bar withSuccess:successBlock];
} else {
// Oh, fake we already did the work.
successBlock(bar);
}
}
Whenever I see the nest level too high I put the inside blocks as normal methods in the class and simply call them inside the block. The effect is the same, but it looks much cleaner, and it allows you to use appledoc or other documentation tools for each method rather than hoping to understand the mess of nested undocumented blocks.
It only gets crazy if you allow it to get crazy.
I have a process that I'm trying to create where I download different xml files and parse them from a website. At the moment I can get them to all work by using...
dispatch_async(dispatch_get_current_queue(),^ { [self updatePersons]; });
dispatch_async(dispatch_get_current_queue(),^ { [self updatePlaces]; });
dispatch_async(dispatch_get_current_queue(),^ { [self updatePositions]; });
dispatch_async(dispatch_get_current_queue(),^ { [self updateContacts]; });
This locks up the main thread because I'm using dispatch_get_current_queue. How can I get these to execute without interrupting each other which seems to be the case when trying the method below.
dispatch_async(dispatch_get_global_queue(0,0),^ { [self updatePersons]; });
The full version of my code I'm using is below, but what happens according to my Log output is they execute at the same time (which I get is kinda the purpose if I understand everything right); however, the code for them never really finishes... I cannot tell if everything is getting parsed or not through the Log Output and the main screen stays frozen. The log only shows part of the logs it should be showing... seems to be interrupted by the other process's NSLog messages.
dispatch_async(dispatch_get_global_queue(0,0),^ { [self updatePersons]; });
dispatch_async(dispatch_get_global_queue(0,0),^ { [self updatePlaces]; });
dispatch_async(dispatch_get_global_queue(0,0),^ { [self updatePositions]; });
dispatch_async(dispatch_get_global_queue(0,0),^ { [self updateContacts]; });
dispatch_async(dispatch_get_global_queue(-2,0),^ {
dispatch_async(dispatch_get_main_queue(),^ {[self setBottomBarToUpdated]; });
});
I'm trying to create a way for the app to pull down the information through each of the functions above, while updating the user on the progress while it's executing by a label on the bottom bar. I have the updating the text working fine it seems by using the below code in each of the four functions...
dispatch_async(dispatch_get_main_queue(),^ {
[self setBottomBarToUpdating:#"Updating Places..."];
});
If anyone can offer help to the proper way to use the queues so my app doesn't lock up I'd greatly appreciate it. Thanks!
If you create you own private concurrent dispatch queue, then you can use a "barrier block". This block will be executed only when all other previously submitted blocks are finished.
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
// These blocks are executed concurrently:
dispatch_async(queue, ^ { [self updatePersons]; });
dispatch_async(queue, ^ { [self updatePlaces]; });
// ...
dispatch_barrier_async(queue, ^ {
// This will be executed when all previous blocks are finished.
dispatch_async(dispatch_get_main_queue(), ^{
[self setBottomBarToUpdated];
});
});
It sounds like you want them to execute sequentially, updating the UI as they progress. If so, you can use a serial queue:
dispatch_queue_t serialQueue = dispatch_queue_create("com.company.MyQueue", NULL);
dispatch_async(serialQueue,^ {
dispatch_async(dispatch_get_main_queue(), ^{
[self setBottomBarToUpdating:#"Updating Persons..."];
}
[self updatePersons];
});
dispatch_async(serialQueue,^ {
dispatch_async(dispatch_get_main_queue(), ^{
[self setBottomBarToUpdating:#"Updating Places..."];
}
[self updatePlaces];
});
dispatch_async(serialQueue,^ {
dispatch_async(dispatch_get_main_queue(), ^{
[self setBottomBarToUpdating:#"Updating Positions..."];
}
[self updatePositions];
});
dispatch_async(serialQueue,^ {
dispatch_async(dispatch_get_main_queue(), ^{
[self setBottomBarToUpdating:#"Updating Contacts..."];
}
[self updateContacts];
dispatch_async(dispatch_get_main_queue(), ^{
[self setBottomBarToUpdating:#"Finished updating"];
}
});
dispatch_release(serialQueue);