use of _block variable in ios7 - ios7

i use this code for assigning value to varible in block i am using ios7 xcode5 its not working for me.
_Block NSString *temp=Nil;
[UIView animateWithDuration:0.7f delay:0.03f usingSpringWithDamping:30.0f initialSpringVelocity:30.0f options:UIViewAnimationOptionCurveLinear animations:^{
[vwBottomMain setFrame:CGRectMake(0.0f, vwBottomMain.frame.origin.y-39, vwBottomMain.frame.size.width,vwBottomMain.frame.size.height)];
} completion:^(BOOL finished) {
temp=#"test";
}];

Although you don't show the rest of this method, the most likely problem is that your completion handler is asynchronous but you're expecting results immediately.
Try running the following code to see what order things are happening in. It should demonstrate that the assignment happens after the test.
__block NSString *temp = nil;
[UIView animateWithDuration:0.7f delay:0.03f usingSpringWithDamping:30.0f initialSpringVelocity:30.0f options:UIViewAnimationOptionCurveLinear animations:^{
NSLog(#"Animation section");
} completion:^(BOOL finished) {
NSLog(#"Completion handler");
temp = #"test";
}];
NSLog(#"String test %#", temp);

Related

How can I guarantee order of subscriber messages in ReactiveCocoa?

I want to do various tasks when self.personsArray is updated as follows:
- (void)viewDidAppear:(BOOL)animated
{
#weakify(self)
[RACObserve(self, personsArray) subscribeNext:^(NSArray *personsArray) {
#strongify(self)
// update a set of views
[self.view setNeedsUpdateConstraints];
[self.view setNeedsLayout];
}];
[RACObserve(self, personsArray) subscribeNext:^(NSArray *personsArray) {
#strongify(self)
// update a second set of views
[self.view setNeedsUpdateConstraints];
[self.view setNeedsLayout];
}];
[RACObserve(self, personsArray) subscribeNext:^(NSArray *personsArray) {
#strongify(self)
[UIView animateWithDuration:0.4 animations:^{
[self.view layoutIfNeeded];
}];
}];
}
I prefer separating the work in distinct blocks because it provides a logical separation. I'd like to guarantee the the last subscription message (the message that executes the animation block) is sent last. How can I do this?
It seems to me that what I'm looking for might be chaining (rather than multiple independent sets of signals as subscriptions, as I've done in this example), but I can't quite connect the dots.
Why don't you just update different parts like this:
- (void)viewDidAppear:(BOOL)animated
{
#weakify(self)
[RACObserve(self, personsArray) subscribeNext:^(NSArray *personsArray) {
#strongify(self)
// update a set of views
[self updateFirstSetOfView];
[self updateSecondSetOfView];
[self doSomethingElse];
// Finally
[UIView animateWithDuration:0.4 animations:^{
[self.view layoutIfNeeded];
}];
}];
}
You could achieve the same with -doNext: if you prefer the chaining.

setNeedsDisplay on uiimageview doesn't refresh the view immediately

I'm using AVCaptureSession to capture an image and then send it to my server.
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
if (imageSampleBuffer != NULL) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
self.videoImageData = [imageData copy];
[self processImage:[UIImage imageWithData:imageData]];
NSString* response=[self uploadImage];
[activityIndicator removeFromSuperview];
self.takePictureBtn.enabled = YES;
[self setUserMessage:response];
}
}];
- (void) processImage:(UIImage *)image
{
...
[UIView beginAnimations:#"rotate" context:nil];
[UIView setAnimationDuration:0.5];
int degrees = [self rotationDegrees];
CGFloat radians =degrees * M_PI / 180.0;
self.captureImageView.transform = CGAffineTransformMakeRotation(radians);
[UIView commitAnimations];
[self.captureImageView setNeedsDisplay];
}
- (NSString*)uploadImage send the photo to the server
The behavior I'm expecting is after processImage terminates that the image will be displayed in the UIImageView captureImageView on it the activity indicator rotates but instead i get a white blanc view with the indicator rotating and only after the server post request terminates captureImageView displays the image
How can I achieve my desired behavior?
Another problem I'm facing is that my imageSampleBuffer returns a mirror image of the taken one (object on the left appears on the right)
From the docs:
This method makes
a note of the request and returns immediately. The view is not
actually redrawn until the next drawing cycle, at which point all
invalidated views are updated.
Since you’re doing other stuff after you call setNeedsDisplay the event doesn’t end and you don’t get a display immediately.
If you want to do more stuff, one approach would be to schedule the rest of the stuff in a new block, like, with
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSString *const response = [self uploadImage];
[activityIndicator removeFromSuperview];
self.takePictureBtn.enabled = YES;
[self setUserMessage:response];
}];

objective c, animation block, delay between animation and completion

I have several animation blocks, all of which follow this basic format with different delays so that they fire one after another:
[UIView animateWithDuration:.85 delay:3 options:opts animations:[animations objectAtIndex:ww] completion:[completions objectAtIndex:ww]];
The options are just UIViewAnimationOptionAutoreverse in a variable for easy access.
I want there to be a delay between the animations and completion so that the images stay in their new position for a little bit before returning to the original one. I've considered using several simpler animateWithDuration:animations: blocks but I didn't see any way to do that with the delay in the documentation, unless I'm missing something.
#Paul.s here's the code I used with what you gave me:
void (^completion)(void) = ^{
[UIView animateWithDuration:.5
delay:5
options:UIViewAnimationCurveLinear
animations:[completions objectAtIndex:ww]
completion:^(BOOL finished) {}];
};
// Call your existing animation with the new completion block
[UIView animateWithDuration:.5
delay:1
options:UIViewAnimationCurveLinear
animations:[animations objectAtIndex:ww]
completion:^(BOOL finished) {
completion();
}];
for reference, the animation is super simple, just moving an image from one point to another and then back. the point at which it crashes is the [UIView animateWithDuration:.5 line where the completion block is defined, and it crashes after the first part of the animation runs.
How about passing another animation to the completion?
Updated
I have updated the code to be the exact working code from the sample I set up. This is using a clean project set up using the Empty Application template
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
CGRect startFrame = CGRectMake(0, 0, 100, 100);
UIView *view = [[UIView alloc] initWithFrame:startFrame];
view.backgroundColor = [UIColor greenColor];
[self.window addSubview:view];
// Set up your completion animation in a block
void (^completion)(void) = ^{
[UIView animateWithDuration:0.5f
delay:0.5f
options:UIViewAnimationCurveLinear
animations:^{
view.frame = startFrame;
}
completion:nil];
};
// Call your existing animation with the new completion block
[UIView animateWithDuration:4
delay:1
options:UIViewAnimationCurveLinear
animations:^{
view.frame = CGRectMake(200, 200, 10, 10);
}
completion:^(BOOL finished) {
completion();
}];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}

Triggering a method after a delay without abusing [UIView animateWithDuration]?

I have a UIViewController that should control 2 UIImageViews to fade in.
I managed to animate them using the UIView animateWithDuration method, like this:
[UIView animateWithDuration:1.5
animations:^{
[mFrontpageTitle setAlpha:0];
[mFrontpageTitle setAlpha:1];
}
completion:^(BOOL finished){
[self AnimatePause];
}];
and
-(void)AnimatePause {
[UIView animateWithDuration:5.0
animations:^{
[mFrontpageTitle setAlpha:0.99];
[mFrontpageTitle setAlpha:1];
}
completion:^(BOOL finished){
[self AnimateAuthor];
}];
which fires the next animation. Now, creating a transition from .99 to 1.0 is not very clean.
Is there a better way to trigger a block or sending a message by just defining a duration?
thanks
Zuppa
NSTimeInterval delay = 1.5; //in seconds
[self performSelector:#selector(myMethod) withObject:nil afterDelay:delay];

Cancel block in UIView animateWithDuration

- (void) startLoading {
[self blink];
}
- (void) blink {
[UIView animateWithDuration:0.5
delay: 0.0
options: UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseOut
animations:^{
//animate stuff
}
completion:^(BOOL finished){
[self blink];
}];
}
- (void) stopLoading {
//What goes here?
}
In my UIView's initWithFrame, I build some loader graphics then start the loader animation from [self startLoading].
The question is now, how do I stop this 'infinite loop'? or what goes in the stopLoading or dealloc method to nicely tear everything down?
When I ignore the fact that a completion block is there and just release my UIView from the super view, everything goes fine for some seconds (more than the 0.5 sec specified) then the app crashes with a message:
malloc: * mmap(size=2097152) failed (error code=12)
error: can't allocate region
** set a breakpoint in malloc_error_break to debug
I have a breakpoint in malloc_error_break and the culprit is the animation block.
I assume that the UIView was released by being removed from the super view and later on the completion block is executed, having a reference to self this is messaging a released object.
I can't find anything in the docs about canceling a 'queued' block.
To cancel, do what you would do with any looping operation you want to be able to cancel: set a flag which you check each time before looping. So:
- (void) stopLoading {
kCancel = YES;
}
And now your completion block looks like this:
completion:^(BOOL finished){
if (!kCancel)
[self blink];
}];
kCancel could be an ivar, a static global variable, whatever.
UIViewAnimationOptionRepeat has magic for u
[UIView animateWithDuration:0.5
delay: 0.0
options: UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionRepeat
animations:^{
//animate stuff
}
completion:^(BOOL finished){
NSLog(#"solved ");
}];
I just repeat the animation and kill it after some time with a dispatch block:
- (void)animate // Blink a view three times
{
// We need to stop the animation after a while (0.9 sec)
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.9 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
{
[view.layer removeAllAnimations];
view.alpha = 0.0; // Animation clean-up
});
[UIView animateWithDuration:0.15 // 0.15*6=0.9: It will animate six times (three in reverse)
delay:0.0
options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat
animations:^{
view.alpha = 1.0; // Animation
}
completion:NULL];
}