hide UIViewController in objective-c - objective-c

I have a home page with table and one button, with pressing my button I will load the qrCode reader view, I want to hide my qrCode view after scan the barcode,
would you please give me some hint what is the best way to do this? NSNOtification or ...
and how?
Thanks in advance!
Here is my qr view code that scans the code:
- (void) readerView:(ZBarReaderView *)readerView didReadSymbols: (ZBarSymbolSet *)symbols
fromImage:(UIImage *)image
{
ZBarSymbol * s = nil;
for (s in symbols)
{
image_view.image = image;
// here I will go to httpReq class for addStamp method
[[HttpReq sharedHttp] setCode:s.data];
[[HttpReq sharedHttp] addStamp];
}
}
Here is my addStamp method that I have to hide the view in this method:
-(void) addStamp
{
// My code was here for connect to api
NSError *jsonError;
NSDictionary* dic = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&jsonError];
if(jsonError != nil)
{
return;
}
// I want to do it here when I have a success or not
BOOL success = [[dic objectForKey:#"success"] boolValue];
if(success){
[self addStampInDB:[[dic objectForKey:#"cardId"] intValue]];
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[dic
objectForKey:#"error"]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert performSelectorOnMainThread:#selector(show) withObject:nil
waitUntilDone:NO];
}
}];
}

Hiding a view in Objective-C is quite simple:
[theView setHidden:YES];

When the addStamp method is called you could invoke a method that is defined in the first class using performSelector or you could follow protocol and delegate mechanism to keep it neat.

Related

iOS EXC_BAD_ACCESS error in class

I'v encountered EXC_BAD_ACCESS error in my app. Or to be more specific in one of my classes. It is Custom UIAlertView class. I couldn't catch when it throws EXC_BAD_ACCESS in usage. Sometimes it works great just as expected, and in all suden it craches... Here is whole class
#implementation AlertPassword
int counter = 3;
#synthesize done;
#synthesize alertText;
#synthesize msg;
- (void) showAlert :(NSString*) title
{
if(counter != 3){
if(counter == 1)
{
NSString *msgs = #"Last warning";
msg = msgs;
}
else
{
NSString *msgs = [NSString stringWithFormat:#"WRONG PIN. %d times remaining",counter];
msg = msgs;
}
}
else
{
NSString *msgs = #"Enter your pin";
msg = msgs;
}
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Security" message:msg delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles: nil];
_alert = alert;
_alert.alertViewStyle = UIAlertViewStyleSecureTextInput;
alertText = [_alert textFieldAtIndex:0];
alertText.keyboardType = UIKeyboardTypeNumberPad;
alertText.placeholder = #"Pin";
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(controlTextDidChange:)
name:UITextFieldTextDidChangeNotification object:alertText];
[_alert show];
[_alert release];
[[NSNotificationCenter defaultCenter] removeObserver:UITextFieldTextDidChangeNotification];
}
- (void)controlTextDidChange:(NSNotification *)notification {
{
NSString *pin = [[NSUserDefaults standardUserDefaults] stringForKey:#"Pin"];
if ([notification object] == alertText)
{
if (alertText.text.length == pin.length)
{
if(counter != 0)
{
if([alertText.text isEqualToString:pin])
{
[_alert dismissWithClickedButtonIndex:0 animated:NO];
[self.tableViewController openSettings];
counter = 3;
}
else
{
counter--;
[_alert dismissWithClickedButtonIndex:0 animated:NO];
[self showAlert:#""];
}
}
else
{
[_alert dismissWithClickedButtonIndex:0 animated:NO];
[[NSUserDefaults standardUserDefaults] setObject:NULL
forKey:#"Telephone"];
[[NSUserDefaults standardUserDefaults] setObject:NULL
forKey:#"Pin"];
[[NSUserDefaults standardUserDefaults] synchronize];
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"" message:AMLocalizedString(#"EraseData", nil) delegate:nil cancelButtonTitle:AMLocalizedString(#"Ok", nil) otherButtonTitles:nil];
counter = 3;
[av show];
[av release];
}
}
}
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *pincheck = [[NSUserDefaults standardUserDefaults] stringForKey:#"pinCheck"];
if (buttonIndex == 0)
{
if(pincheck.intValue == 1)
{
NSLog(#"app kill");
exit(0);
}
else
{
NSLog(#"dismiss");
}
}
}
#end
Here is where i initialize and use this class.
case 5:
NSLog(#"Add remove");
if (pincheck != NULL && pin != NULL){
if([pincheck isEqualToString:#"0"])
{
AlertPassword *alert = [AlertPassword alloc];
alert.tableViewController = self;
NSString *msg = #"Enter your pin code to access:";
[alert showAlert:msg];
// [alert release];
}
break;
}
else
{
NSLog(#"Is null");
[Menu load2View:self];
}
break;
I though maybe it was because i do not release alert. But adding [alert release]; Made to have EXC_BAD_ACCESS directly after the user tries to enter something. Without [alert release]; it works. But sometimes it craches with EXC_BAD_ACCESS
Also sometimes it gets
2012-11-08 12:11:27.451 kodinisRaktas[2485:19d03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSMallocBlock__ dismissWithClickedButtonIndex:animated:]: unrecognized selector sent to instance 0x947aae0'
But I also have no idea why this happends
Please help, I'm pretty new to objective-c and ios, and I have no idea how to get rid of this, I guess someone with a bit of experience will see whats wrong in my code.
I'v just saw, that EXC_BAD_ACCESS or unrecognized selector throws if you push cancel for 4-5 times or more, and then try to type something.
EXC_BAD_ACCESS is mostly due to bad memory handling. The alert has most likely become an zombie... I would have the alert as a property with strong/retain. You should hold on to it while displaying. Not release after "show".
When you set up the first you can do like this
_alert = [[UIAlertView alloc] initWithTitle:#"Security" message:msg delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles: nil]; // retain count: 1
Note calling "show" will also retain it, but that does not change the fact that you need to too.
[_alert show]; // retain count: 2
Wait for the delegate callback and release it.
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
[_alert release], _alert = nil; // retain count in next run will be 0
}
Tip: It may be easier to handle if you use UIAlertView combined with blocks. http://gkoreman.com/blog/2011/02/15/uialertview-with-blocks/
I don't see where you initialize alert, anyway I suppose it's a class field, so retain it.If it's not a class instance variable, make it be so, this way you will always have a pointer to it.
[__NSMallocBlock__ dismissWithClickedButtonIndex:animated:]
You are sending this message to a raw malloc block, so probably alert has been released and points to a memory used for something else, something that's not an objc object.
Try to retain alert and see what happens.
May be you are passing wrong values to this "dismissWithClickedButtonIndex:animated:" method which is not recognizing the value signature please do a double check for that;
the excepted answer does make sense and is likely the cause
but what is this?
[NSNotificationCenter defaultCenter] removeObserver:UITextFieldTextDidChangeNotification];

iOS Mail Composer Won't Dismiss

I am trying to take a screenshot and email it using the mail composer. Everything works great except the mail composer won't dismiss. This post seems to have the same problem, but the solution provided did not work for me. Can't dismiss the email composer view in iPhone?
- (IBAction)Email:(id)sender {
UIGraphicsBeginImageContext(self.view.frame.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * imageData = UIImageJPEGRepresentation(image, 1.0);
if ( [MFMailComposeViewController canSendMail] ) {
MFMailComposeViewController * mailComposer = [[[MFMailComposeViewController alloc] init] autorelease];
mailComposer.delegate = self;
[mailComposer setSubject:#"Risk Assessment"];
[mailComposer addAttachmentData:imageData mimeType:#"image/jpeg" fileName:#"attachment.jpg"];
[self presentModalViewController:mailComposer animated:YES];
}
}
The above code works great. How do I call this bottom portion. It seems like the compiler just skips past it.
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{
if (error){
NSString *errorTitle = #"Mail Error";
NSString *errorDescription = [error localizedDescription];
UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:errorTitle message:errorDescription delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[errorView show];
[errorView release];
}
[controller dismissModalViewControllerAnimated:YES];
}
Thanks in advance.
Try
mailComposer.mailComposeDelegate = self;
instead of
mailComposer.delegate = self;
From the MFMailComposeViewController documentation:
#property(nonatomic,assign) id<MFMailComposeViewControllerDelegate> mailComposeDelegate;
The delegate object is responsible for dismissing the view presented by this view controller at the appropriate time. Therefore, you should always provide a delegate and that object should implement the methods of the MFMailComposeViewControllerDelegate protocol.
I am pretty sure that last line should be
[self dismissModalViewControllerAnimated:YES];
The ViewController that presented the view modally, also dismisses it.

reading a value from preferences

I have just recently implemented the inAppSettings kit. My goal was to load my default view and then add a navigation bar button item to the right called "settings". Once the user pressed the settings button it would take them to my settings bundle where they would make a choice to which website they wanted, and then press back which would load up my default view once again with webview loaded once again with the new url.
I have implemented everything that I just described above but once the selection is made within the settings and the user presses back (aka dismisses the settings view to go back to the default view), the app crashes and I have no idea why. My code is below and if anyone knows why this is happening, it would be much appreciated. Let it be noted that once I run the app again after it crashes, the website loads correctly based on the settings they chose before it crashed.
P.S. the options the user can click to select are: Google, stackoverflow.
ERROR Message: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Upcoming settingsViewControllerDidEnd:]: unrecognized selector sent to instance 0x281c70'
Thank you in advance
- (IASKAppSettingsViewController*)appSettingsViewController {
if (!appSettingsViewController) {
appSettingsViewController = [[IASKAppSettingsViewController alloc] initWithNibName:#"IASKAppSettingsView" bundle:nil];
appSettingsViewController.delegate = self;
}
return appSettingsViewController;
}
-(IBAction)selectSettings {
UINavigationController *aNavController = [[UINavigationController alloc] initWithRootViewController:self.appSettingsViewController];
//[viewController setShowCreditsFooter:NO]; // Uncomment to not display InAppSettingsKit credits for creators.
// But we encourage you not to uncomment. Thank you!
self.appSettingsViewController.showDoneButton = YES;
[self presentModalViewController:aNavController animated:YES];
[aNavController release];
}
-(NSDictionary *)intialDefaults {
NSArray *keys = [[[NSArray alloc] initWithObjects:kPicture, nil] autorelease];
NSArray *values= [[[NSArray alloc] initWithObjects: #"none", nil] autorelease];
return [[[NSDictionary alloc] initWithObjects: values forKeys: keys] autorelease];
}
-(void)setValuesFromPreferences {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults registerDefaults:[self intialDefaults]];
NSString *picturePreference= [userDefaults stringForKey:kPicture];
if([picturePreference isEqualToString:#"google"]) {
[self getUpcoming:#"http://www.google.ca"];
} else
if ([picturePreference isEqualToString:#"stackoverflow"]) {
[self getUpcoming:#"http://www.stackoverflow.com"];
} else {
[self getUpcoming:#"http://www.yahoo.com"];
}
}
-(void)getUpcoming:(id) hello {
NSURL *url= [NSURL URLWithString:hello];
NSURLRequest *requestURL= [NSURLRequest requestWithURL:url];
[web loadRequest:requestURL];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
web.hidden=NO;
[spinner stopAnimating];
[load_message dismissWithClickedButtonIndex:0 animated:TRUE];
pic1.hidden=YES;
}
-(void) loadMethod {
load_message = [[UIAlertView alloc] initWithTitle:#"Loading..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
spinner= [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(135.0, 60.0);
[load_message addSubview:spinner];
[load_message show];
[spinner startAnimating];
[self performSelector:#selector(setValuesFromPreferences) withObject:nil afterDelay:0.0];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UIBarButtonItem *settingButton= [[UIBarButtonItem alloc]
initWithTitle:#"Settings"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(selectSettings)];
self.navigationItem.rightBarButtonItem = settingButton;
web.hidden=YES;
pic1.hidden=NO;
}
- (void) viewDidAppear:(BOOL)animated {
[self loadMethod];
}
Do you implement the InAppSettingKit delegate? Add this to your current class above
- (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController *)sender
{
// dismiss the view here
[self dismissModalViewControllerAnimated:YES];
// do whatever you need to do
}

Displaying UIAlertViews Sequentially

I have several UIAlertViews that i want to display in a sequential order, and only move on to display the next UIAlertView once the previous one has been dismissed (by user clicking okay).
I know about the didDismissWithButtonIndex delegate and adding a tag, but this doesn't really help too much as there could be upto 3 UIAlertViews invoked and not necessarily in the same order everytime. see code:
if(condition 1){
alert1 = // UIAlertView[[.....
[alert1 show]
}
if(condition 2){
alert2 = // UIAlertView[[.....
[alert2 show]
}
if(condition 3){
alert3 = // UIAlertView[[.....
[alert3 show]
}
The above will just add 3 Alerts on top of each other (depending on how many conditions are met) which is not what I want. I want to be able to only show one at a time and then the next one (if there is one) after the user hits the ok button.
I had the idea of maybe adding the messages to a queue and then processing that queue removing the alert every time an alert is dismissed but i'm not sure how id go about doing that.
Any ideas would be much appreciated.
Thanks
You could easily do it in the UIAlertView delegate method, called once an alert view is dismissed. So, UIAlertViewDelegate defines the following delegate method:
– alertView:didDismissWithButtonIndex:
Implement that method, and make sure your class is the delegate of the UIAlertViews you create. This method is the perfect place to then show the next alert based on the one being dismissed by the user.
If your requirement is "Display up to three alerts, sequentially, but not always in the same order" i'd probably put the alerts in to an array, and then in the delegate method get the next alert out of the array to show. It doesn't have to be any more complex than that really; the key thing is that the delegate method implementation is the best place to show the next alert.
Pseudo Code Example:
Define an array; NSMutableArray * alerts_;
- (void)showAlertSequence {
if ( !alerts_ ) {
alerts_ = [[NSMutableArray alloc] init];
}
[alerts_ addObjects;<My alerts>];
[self showSequencedAlertFrom:nil];
}
- (BOOL)showSequencedAlertFrom:(UIAlertView *)sourceAlertView {
if ( !sourceAlertView ) {
[[alerts_ objectAtIndex:0] show];
}
else {
NSInteger index = [alerts_ indexOfObject:sourceAlertView];
if ( index < [alerts_ count] ) {
[[alerts_ objectAtIndex:index++] show];
}
}
return NO;
}
– alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)index {
// Show the next alert or clean up if we're at the end of the sequence.
if ( ![self showSequencedAlertFrom:alertView] ) {
[alerts_ removeAllObjects];
}
}
As an aside; three sequential alerts will really annoy you users ;)
One thing that I've done is used block based UIAlertViews by adding a category on AlertView.
Here is the .h file
#interface UIAlertView (WithBlocks)
- (id) initWithTitle:(NSString *)title message:(NSString *)message;
- (void) addButtonWithTitle:(NSString *)title andBlock:(void(^)())block;
#end
Here is the .m file
static NSString *BUTTON_BLOCK_KEY = #"alertview-button-blocks";
#interface UIAlertView()
- (void) runBlock: (void (^)())block;
#end
#implementation UIAlertView (WithBlocks)
/**
* Initialized an alert view with a title and message.
*/
- (id) initWithTitle:(NSString *)title message:(NSString *)message
{
self = [self initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
if (self) {
self.delegate = self;
NSMutableArray *buttonBlocks = [NSMutableArray array];
objc_setAssociatedObject(self, BUTTON_BLOCK_KEY, buttonBlocks, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return self;
}
/**
* Adds a button with a title and a block to be executed when that button is tapped.
*/
- (void) addButtonWithTitle:(NSString *)title andBlock:(void (^)())block
{
// Add the button
[self addButtonWithTitle:title];
NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
if (!block) {
block = ^{ /* empty block */ };
}
[buttonBlocks addObject:[[[block copy] retain] autorelease]];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
void (^block)() = (void (^)()) [buttonBlocks objectAtIndex:buttonIndex];
// Due to a timing issue, the current window is still the UIAlertView for a very
// short amount of time after it has been dismissed which messes up anything
// trying to get the current window in the blocks being run.
// Ergo, the block is being delayed by a tiny bit. (Amount determined through limited testing)
[self performSelector:#selector(runBlock:) withObject:block afterDelay:0.25];
}
- (void) runBlock: (void (^)())block
{
block();
}
#end
Then you can call chain the alertviews together by the following code
void(^continueBlock)(void) = ^{
// Display more alertviews here
};
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"message"];
[alert addButtonWithTitle:#"Continue" andBlock:continueBlock];
[alert addButtonWithTitle:#"Dismiss" andBlock:^{
// Display more alertviews here
}
[alert show];
[alert release];
I was looking for a solution to this problem as well. Here's the way I ended up solving it for my own app:
static BOOL alertShowing = FALSE;
UIAlertView *alert0 = [[UIAlertView alloc] initWithTitle:#"AlertView 0" message:#"This is the first alert" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Yes",#"No", nil];
[alert0 setTag:0];
alertShowing = TRUE;
[alert0 show];
while (alertShowing) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
}
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:#"AlertView 1" message:#"This is the second alert" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Yes",#"No", nil];
[alert1 setTag:1];
alertShowing = TRUE;
[alert1 show];
while (alertShowing) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
}
// add some more alerts here for dramatic effect ...
Your button handler must set alertShowing = FALSE' in every exit path.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// Deal with handling responses for your different alerts here.
switch ([alertView tag]) {
case 0:
// handler first alert here
break;
case 1:
// handler second alert here
break;
default:
// etc.
break;
}
alertShowing = FALSE;
}
There may be better ways to sit and spin than creating a new run loop, and there's some duplicate code that probably could be genericized better. On the plus side, it's straightforward and doesn't require a bunch of queuing logic. I'm using a #define for this pattern to keep from having to hand-type it, and it has worked fine in my case.
Here's how I did it using a queue of alert's like you suggested.
#property (strong, nonatomic) NSMutableArray *alertQueue;
#property (nonatomic) BOOL showingAlert;
- (void)showAlert:(UIAlertView *)alert {
if (self.showingAlert) {
[self.alertQueue addObject:alert];
}
else {
self.showingAlert = YES;
[alert show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([self.alertQueue count]) {
UIAlertView *alert = [self.alertQueue objectAtIndex:0];
[self.alertQueue removeObjectAtIndex:0];
[alert show];
}
else self.showingAlert = NO;
}
Then whenever you want to display an alert, you just create the UIAlertView and pass it to the showAlert method and it will only show up after all earlier alerts have been dismissed.

EXC_BAD_ACCESS error using ALAssetsLibrary assetForURL:resultBlock:failureBlock:

I'm trying to read the EXIF data from an image, selected by a user. I'm using the ALAssetLibrary for this. So far I've managed to get the reference URL needed for the assetForURL:resultBlock:failureBlock: method, but when I try to do anything with the reference URL i get a EXC_BAD_ACCESS error.
An NSLog of the URL, right before using it, results in the (correct, as far as i know) string:
assets-library://asset/asset.JPG?id=1000000003&ext=JPG
I've been trying to figure this out, but I seem to be hitting a dead end each time. I must admit I'm new to Objective-C in general, so please feel free to criticize my code accordingly.
Code (far from the complete classes, but i think it should be sufficient):
//Class_X.m
-(void)readExifDataFromSelectedImage:(NSURL *)imageRefURL
{
void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *) = ^(ALAsset *asset)
{
NSLog(#"Test:Succes");
};
ALAssetsLibrary *myAssetLib;
NSLog(#"%#",imageRefURL);
[myAssetLib assetForURL:imageRefURL
resultBlock:ALAssetsLibraryAssetForURLResultBlock
failureBlock:^(NSError *error){NSLog(#"test:Fail");}];
}
//Class_Y.m
//This also conforms to the UIImagePickerControllerDelegate And the NavigationControllerDelegate protocols:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.referenceURL = [info valueForKey:#"UIImagePickerControllerReferenceURL"];
NSString *mediaType = [info
objectForKey:UIImagePickerControllerMediaType];
[self dismissModalViewControllerAnimated:YES];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
UIImage *selectedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
imageView.image = selectedImage;
btnNoPicture.hidden = YES;
btnSelectPicture.hidden = YES;
btnTakePicture.hidden = YES;
imageView.hidden = NO;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Use this image?"
message:#"Are you sure you want to use this image?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[alert show];
[alert release];
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
//Do not use the selected image.
imageView.image = nil;
imageView.hidden = YES;
//Restart picking process
}
else
{
// I have an instance variable of type Class_X which i use
// throughout this class; let's call this variable "report".
// I also have the referenceURL stored as an instance variable.
[self.report readExifDataFromSelectedImage:self.referenceURL];
}
}
EXC_BAD_ACCESS is most often the result of an over-released object (dangling pointer). As the library operates asynchronously, your block is executed after the readExifDataFromSelectedImage: method has returned, so imageRefURL is probably already deallocated at this point. Try to retain the URL before requesting the asset and release it in the success and failure blocks.