Any one know how to reload collectionView in parentViewController when removing childViewController.
Here, I am processing on click of button adding childViewController and on click of that childViewController I am getting data and that data will transferred to parentViewController after that child view get's remove from parentViewController.
I am getting data from childViewController, also reloading collection view.
dispatch_async(dispatch_get_main_queue(),^{
[self.view layoutIfNeeded];
[self.collectionViewcellItem layoutIfNeeded];
[self.collectionViewcellItem reloadData];
});
but, no effect of reloading here seen.
means not able to change parentviewconroller view after removal of childViewController.
Thank you
Waiting for the answer and yes I am doing it in objective c.
parentViewController file.
[self.view addSubview:filterMenuVC.view];
filterMenuVC.view.backgroundColor = [UIColor clearColor];
[self addChildViewController:filterMenuVC];
[self.view addSubview:filterMenuVC.view];
[self animationSideFilterMenuBarOpen];
[filterMenuVC didMoveToParentViewController:self];
childViewController file
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",[NSString stringWithFormat:#"%ld",(long)indexPath.row]);
// // [wel animationSideFilterMenuBarClose];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
int categoryId = (int)cell.textLabel.tag;
[self animationSideMainMenuBarClose:categoryId];
}
-(void)animationSideMainMenuBarClose:(int)categoryId{
CGFloat width = [UIScreen mainScreen].bounds.size.width;
self.view.frame = CGRectMake(width - self.view.frame.size.width, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
[UIView animateWithDuration:0.5 animations:^{
self.view.frame = CGRectMake(width, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
}
completion:^(BOOL finished){
[self.view removeFromSuperview];
self.view = nil;
NSLog(#"category id Filter: %d",categoryId);
BOOL boolresponse = [wel getUserWork:categoryId];
if (boolresponse == NO) {
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:#""
message:#"No internet connection"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okButton = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
}
}];
}
here, BOOL boolresponse = [wel getUserWork:categoryId]; getUserWork is the function in parentViewController, I call that and removing the childViewController. get correct data but not able to reload collectionView.
parentViewFunction which I am calling.
-(BOOL)getUserWork:(int)catergoryId{
appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
[self dismissViewControllerAnimated:true completion:^{
//do whatever you do here
[self.collectionViewcellItem reloadData];
}];
categoryIdStart = catergoryId;
Reachability *r = [[Reachability alloc]init];
if(r.currentReachabilityStatus != NotReachable) {
return NO;
}
else
{
[SVProgressHUD show];
[SVProgressHUD setStatus:#"Loading..."];
[SVProgressHUD setRingRadius:20];
[SVProgressHUD setRingThickness:10];
[SVProgressHUD setBorderColor:[UIColor orangeColor]];
[SVProgressHUD setBorderWidth:0.5];
[SVProgressHUD setForegroundColor:[UIColor orangeColor]];
NSLog(#"id category: %d",categoryIdStart);
NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:[appDelegate.UserDic valueForKey:#"token"],#"token",[appDelegate.UserDic valueForKey:#"id"],#"id_user",[NSString stringWithFormat:#"%d",categoryIdStart],#"id_category",nil];
NSMutableArray *postArray = [NSMutableArray array];
[params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
[postArray addObject:[NSString stringWithFormat:#"%#=%#", key, [apiCall percentEscapeString:obj]]];
}];
NSString *postString = [postArray componentsJoinedByString:#"&"];
[apiCall apiType:#"xyzzy" pD:postString dataRetrive:^(NSDictionary *dictionary){
int status = [[dictionary valueForKey:#"status"] intValue];
if (status == 0) {
[SVProgressHUD dismiss];
dispatch_async(dispatch_get_main_queue(),^{
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:#""
message:[dictionary valueForKey:#"msg"]
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okButton = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
});
}
else{
[SVProgressHUD dismiss];
[cacheImage removeAllObjects];
dic = [dictionary valueForKey:#"data"];
NSLog(#"Category detail: %# %lu",dic,(unsigned long)dic.count);
NSLog(#"image category %# :",[dic valueForKey:#"category_name"]);
dispatch_async(dispatch_get_main_queue(),^{
[self.view layoutIfNeeded];
[self.collectionViewcellItem layoutIfNeeded];
[self.collectionViewcellItem reloadData];
[self viewWillAppear:true];
});
}
}];
return YES;
}
}
Related
The app I'm working on is using a function that is working fine but blocks the main thread. I am attempting to add a loading spinner using SVProgressHUD and that requires I call my function asynchronously in order to display the spinner. As soon as I call the function asynchronously however the app crashes with EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0 The only change I have made to the function is to invoke the popViewControllerAnimated lines on the main thread. Why is running this code on a new thread causing it to crash and how can I fix it?
Calling code:
-(void) _doSaveDataPoint {
[SVProgressHUD show];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self _saveDataPoint];
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
});
}
_saveDataPoint function. popViewController called on main thread near the end of this code:
-(void) _saveDataPoint {
NSString *errorMsg = nil;
if ([[myLegend type] isEqualToString:#"PIN"]) {
if ([myNodes count]==0) {
errorMsg = #"Please make sure you have added one point on to the map to continue.";
}
}
else if ([[myLegend type] isEqualToString:#"POLYGON"]) {
if ([myNodes count]<3) {
errorMsg = #"Please make sure you have at least 3 points set before continuing.";
}
}
else {
if ([myNodes count]<2) {
errorMsg = #"Please make sure you have at least 2 points set before continuing.";
}
}
if (errorMsg !=nil) {
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:#"Not enough points"
message:errorMsg
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
// Just dismiss
}];
[alertController addAction:okAction];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:alertController animated:YES completion:nil];
});
return;
}
ClientLegendDataPointBounds *bounds = [[ClientLegendDataPointBounds alloc] init];
int count = 0;
GeoPoint *first = nil;
NSMutableDictionary *attr = [[NSMutableDictionary alloc] init];
for (_EditAnnotation *anno in myNodes) {
GeoPoint *point = [[GeoPoint alloc] initWithLatitude:[anno coordinate].latitude andLongitude:[anno coordinate].longitude];
[bounds expand:point];
if (count==0) {
first = point;
count++;
continue;
}
NSString *xKey = [NSString stringWithFormat:#"x%d",count-1];
NSNumber *xCoord = [NSNumber numberWithDouble:[point latitude ]];
NSString *yKey = [NSString stringWithFormat:#"y%d",count-1];
NSNumber *yCoord = [NSNumber numberWithDouble:[point longitude]];
[attr setObject:xCoord forKey:xKey];
[attr setObject:yCoord forKey:yKey];
count++;
}
if (count>0) {
NSString *pointCount = [NSString stringWithFormat:#"%d", count-1];
[attr setObject:pointCount forKey:#"pointCount"];
}
[self _setBarThemeDefault];
if (myDataPoint==nil) {
myDataPoint = [myLegend addDataPoint:[NSNumber numberWithLongLong:[DateTime currentTimeInMillis]] title:#"" description:#"" latitude:[first latitude] longitude:[first longitude] attributes:attr type:[myLegend type] bounds:bounds];
dispatch_async(dispatch_get_main_queue(), ^{
[[self navigationController] popViewControllerAnimated:NO];
});
[myHandler newItemCreated:myDataPoint];
} else {
[myDataPoint setAttributes:attr];
[myDataPoint setBounds:bounds];
[myDataPoint setLatitude:[first latitude]];
[myDataPoint setLongitude:[first longitude]];
[myDataPoint setModified:[NSNumber numberWithLongLong:[DateTime currentTimeInMillis]]];
[myDataPoint update];
dispatch_async(dispatch_get_main_queue(), ^{
[[self navigationController] popViewControllerAnimated:YES];
});
[myHandler itemUpdated:myDataPoint];
}
[self _finishSurveyLog:[SurveyLogItem ACT_SAVE_SPATIAL_CONST]];
[self _saveUserLocation];
}
I don't know exactly the plugin but could it be that the plugin itselfs dispatches the ui stuff to the main queue? So you don't have to dispatch the call to the main queue by yourself. Take a look at the source code:
SVProgressHUD.m
I am developing an app.I have a problem while developing the app.
The problem is:
I have a UIImageView and audio.I have 20 images in an array .so i need to display the 20 images in this UIImageView within time interval.Along with the image i need to set the audio.I need to view in same time, ie 20 images and audio should come at same time.
my code as below.
alphabetsStoreArray = [[NSMutableArray alloc]initWithObjects:#"a.png",#"b.png",#"c.png",#"d.png",#"e.png",#"f.png",#"g.png",#"h.png",#"i.png",#"j.png",#"k.png",#"l.png",#"m.png",#"n.png",#"o.png",#"p.png",#"q.png",#"r.png",#"s.png",#"t.png",#"u.png",#"v.png",#"w.png",#"x.png",#"y.png",#"z.png", nil];
commonFunctionObject = [[SpeechCommonFunctions alloc]init];
commonFunctionObject.isRecordComplete = NO;
counter = 0;
isMicPresent = YES;
_confirmationPopupView.hidden = true;
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(repeatActionFire) userInfo:nil repeats:NO];
// Do any additional setup after loading the view.
}
-(void)repeatActionFire
{
if(counter >= alphabetsStoreArray.count)
{
NSLog(#"finished");
[_alphabetsShowImageView removeFromSuperview];
[_speakerOrMicImageView removeFromSuperview];
UIImageView *congratzView = [[UIImageView alloc]initWithFrame:self.view.frame];
congratzView.image = [UIImage imageNamed:#"congratulation.png"];
[self.view addSubview:congratzView];
[self performSelector:#selector(navNew) withObject:nil afterDelay:3];
}
else
{
[commonFunctionObject textToSpeechAction:alphabetsStoreArray :counter :_alphabetsShowImageView :_speakerOrMicImageView :isMicPresent];
[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(ActionToCkeckRecordCompletion) userInfo:nil repeats:YES];
}
}
-(void)ActionToCkeckRecordCompletion
{
if(commonFunctionObject.isRecordComplete)
{
_confirmationPopupView.hidden = false;
}
}
-(void)navNew
{
v11=[self.storyboard instantiateViewControllerWithIdentifier:#"maincontroller"];
[self presentViewController:v11 animated:NO completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
} */
-(IBAction)homebut:(id)sender{
UIAlertController * alert=[UIAlertController alertControllerWithTitle:#"Title"
message:#"Message"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* Home = [UIAlertAction
actionWithTitle:#"RETURN TO HOME"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
v11=[self.storyboard instantiateViewControllerWithIdentifier:#"maincontroller"];
[self presentViewController:v11 animated:NO completion:nil];
}];
UIAlertAction* Cancel = [UIAlertAction
actionWithTitle:#"CANCEL"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
}];
[alert addAction:Cancel];
[alert addAction:Home];
[self presentViewController:alert animated:YES completion:nil];
}
- (IBAction)playButtonAction:(id)sender
{
[commonFunctionObject recordPlayAction];
}
- (IBAction)nextButtonAction:(id)sender
{
counter+=1;
_confirmationPopupView.hidden = true;
commonFunctionObject.isRecordComplete = NO;
if(commonFunctionObject.player.playing){[commonFunctionObject.player stop];}
[self repeatActionFire];
}
- (IBAction)retryButtonAction:(id)sender
{
_confirmationPopupView.hidden = true;
commonFunctionObject.isRecordComplete = NO;
if(commonFunctionObject.player.playing){[commonFunctionObject.player stop];}
[self repeatActionFire];
}
how to do?
Try this, May be you need more than this, but here is a start to get you in the right direction.
-(IBAction)btnclicked:(id)sender {
NSMutableArray *images = [[NSMutableArray alloc]init];
//all alloc does is allocate memory. The -init method is crucial to
actually initialize the object into a working state.
for (int imagenumber = 1; imagenumber <= 45; imagenumber++) {
NSMutableString *myString = [NSMutableString stringWithFormat:#"%i.png", imagenumber];
[images addObject:[UIImage imageNamed:myString]];
}
CGRect frame = CGRectMake(0.0, 0.0, 320, 460);
UIImageView *imageview = [[UIImageView alloc] initWithFrame:frame];
imageview.contentMode = UIViewContentModeScaleToFill;
NSURL *url = [NSURL fileURLWithPath:[NSString
stringWithFormat:#"%#/giggity stick around.wav", [[NSBundle mainBundle]
resourcePath]]];
soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url
error:nil];
soundPlayer.volume = 1;
[soundPlayer play];
imageview.animationImages = images;
imageview.animationDuration = 3.2;
imageview.animationRepeatCount = 1;
[imageview startAnimating];
[self.view addSubview:imageview];
}
Use the AVFoundation to play the audio.
After clicking post to the share dialog, the Host App(e.g. Safari) hangs up if arrSites variable is currently not empty. I can only store 1 object inside my arrSites variable. How can I addObject to my NSMutableArray variable?
Below is my implemented code and it generates an error in [arrSites addObject:dictSite] line.
- (void)didSelectPost
{
inputItem = self.extensionContext.inputItems.firstObject;
NSItemProvider *urlItemProvider = [[inputItem.userInfo valueForKey:NSExtensionItemAttachmentsKey] objectAtIndex:0];
if ([urlItemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypeURL])
{
NSLog(#"++++++++++ Attachment is a URL");
[urlItemProvider loadItemForTypeIdentifier:(__bridge NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error)
{
if (error)
{
NSLog(#"Error occured");
}
else
{
NSMutableArray *arrSites;
if ([sharedUserDefaults valueForKey:#"SharedExtension"]){
arrSites = [sharedUserDefaults objectForKey:#"SharedExtension"];
}else{
arrSites = [[NSMutableArray alloc] init];
}
NSDictionary *dictSite = [NSDictionary dictionaryWithObjectsAndKeys:self.contentText, #"Text", url.absoluteString, #"URL",nil];
[arrSites addObject:dictSite];
[sharedUserDefaults setObject:arrSites forKey:#"SharedExtension"];
[sharedUserDefaults synchronize];
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:#"Success"
message:#"V7 Posted Successfully."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[UIView animateWithDuration:0.20 animations:^
{
self.view.transform = CGAffineTransformMakeTranslation(0, self.view.frame.size.height);
}
completion:^(BOOL finished)
{
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
}];
}];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
}];
}
}
Without memory allocation you can't add the object to array, use like
// allocate the memory of array in before
NSMutableArray *arrSites = [[NSMutableArray alloc] init];
if ([sharedUserDefaults valueForKey:#"SharedExtension"]){
[arrSites addObjectsFromArray:[sharedUserDefaults objectForKey:#"SharedExtension"]];
}
[arrSites addObject:dictSite];
Most likely the source of the problem is that
arrSites = [sharedUserDefaults objectForKey:#"SharedExtension"];
creates immutable object (NSArray instead of NSMutableArray). You can fix this issue using
arrSites = [[sharedUserDefaults objectForKey:#"SharedExtension"] mutableCopy];
instead.
instead of a button i'd like to change the view controller if a alert is validated but i've no idea how to do is. I use a cocoa pod for the notification (just cause the design is beautiful). every answer is welcome!
- (IBAction)changeTheme:(UIButton *)sender {
// for changing view controller
[UIView animateKeyframesWithDuration:1.0 delay:0 options:0 animations:^{
changeTheme.transform = CGAffineTransformMakeScale(2, 2);
} completion:^(BOOL finished) {
// init alert with options
SCLAlertView *changeThemeNotification = [[SCLAlertView alloc] init];
// to sport
[changeThemeNotification addButton:#"change to sport" validationBlock:^BOOL{
BOOL passedValidation = true;
return passedValidation;
} actionBlock:^{
}];
// to food
[changeThemeNotification addButton:#"change to food" validationBlock:^BOOL{
BOOL passedValidation = true;
return passedValidation;
} actionBlock:^{
[self.view setBackgroundColor:[UIColor blackColor]];
}];
// to animal
[changeThemeNotification addButton:#"change to animal" validationBlock:^BOOL{
BOOL passedValidation = true;
return passedValidation;
} actionBlock:^{
[self.view setBackgroundColor:[UIColor greenColor]];
}];
// else (message & options)
[changeThemeNotification showCustom:self image:nil color:[self.colorWheel randomColor] title:#"Test" subTitle:#"This is a test notification for the navigation." closeButtonTitle:#"stay" duration:0.0f];
changeThemeNotification.hideAnimationType = SlideOutToBottom;
changeThemeNotification.shouldDismissOnTapOutside = YES;
changeThemeNotification.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/url_to_sound.mp3", [[NSBundle mainBundle] resourcePath]]];
}];
}
try this
SCLAlertView *changeThemeNotification = [[SCLAlertView alloc] init];
[changeThemeNotification addButton:#"change to sport" validationBlock:^BOOL{
BOOL passedValidation = true;
return passedValidation;
} actionBlock:^{
[self performSegueWithIdentifier:#"yourSegueName" sender:self];
}];
The following code will help:
To check the iOS version:
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
To display the alert view:
if(SYSTEM_VERSION_LESS_THAN(#"8.0"))
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#""
message:#"your message"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil];
[alert show];
}
else
{
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:#""
message:#"You message..."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction
actionWithTitle:NSLocalizedString(#"OK", #"OK action")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action)
{
[self performSegueWithIdentifier:#"yourSegueName" sender:self];
}];
[alertController addAction:okAction];
[self presentViewController:alertController animated:YES completion:nil];
}
Also use the following code to handle "ok" button for iOS <8.0.
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
{
[self performSegueWithIdentifier:#"yourSegueName" sender:self];
}
else
{
}
}
Is anyone else having an issue with UIImagePickerController in iOS 8? The method below works perfectly well in iOS 7 on an iPad, but I get the following error when I run this in XCode 6 (Beta 3 or 4) when I try to present the picker (last line). If it matters, the selection of the sourceType is coming from an alertView that is presented in the same place.
Warning: Attempt to present <UIImagePickerController: 0x7c0ae400> on <CAGUCreateContactViewController: 0x7bf61a00> which is already presenting (null)
Method to open imagePicker.
- (void)openPhotoPicker:(UIImagePickerControllerSourceType)sourceType
{
if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {
NSArray *availableMediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType];
if ([availableMediaTypes containsObject:(NSString *)kUTTypeImage]) {
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.modalPresentationStyle = UIModalPresentationFullScreen;
imagePickerController.sourceType = sourceType;
imagePickerController.mediaTypes = #[(NSString *)kUTTypeImage];
imagePickerController.delegate = self;
self.imagePickerController = imagePickerController;
if (sourceType == UIImagePickerControllerSourceTypeCamera) {
[self presentViewController:self.imagePickerController animated:YES completion:nil];
} else {
if (self.popoverVC) {
[self.popoverVC dismissPopoverAnimated:YES];
self.popoverVC = nil;
}
self.popoverVC = [[UIPopoverController alloc] initWithContentViewController:imagePickerController];
[self.popoverVC presentPopoverFromRect:self.nameAndPicCell.picture.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
}
}
}
I think this is because in iOS 8, alert views and action sheets are actually presented view controllers (UIAlertController). So, if you're presenting a new view controller in response to an action from the UIAlertView, it's being presented while the UIAlertController is being dismissed. I worked around this by delaying the presentation of the UIImagePickerController until the next iteration of the runloop, by doing this:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self openPhotoPicker:sourceType];
}];
However, the proper way to fix this is to use the new UIAlertController API on iOS 8 (i.e. use if ([UIAlertController class]) ... to test for it). This is just a workaround if you can't use the new API yet.
I agree with Ben Lings issue detection. I would suggest a simpler solution in case when using UIActionSheet. I simply moved my code that reacts on Action Sheet selection from:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex;
{
// my code
}
into:
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex; // after animation
{
// my code
}
This way app is guarantied that code will be executed AFTER UIActionSheet animation finishes.
Since UIAlertView has similar delegate method:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex; // after animation
{
// my code
}
I suppose that similar solution may apply.
Here is a solution that worked for me
if([[[UIDevice currentDevice] systemVersion] floatValue]>=8.0)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self presentViewController:cameraUI animated:NO completion:nil];
}];
}
else{
[controller presentViewController:cameraUI animated:NO completion:nil];
}
Remember to alloc cameraUI
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
Build and Go!
I was facing the same problem in iOS 8.
Then I saw the change log of the latest update to iOS i.e. 8.0.2 on the device.
It is mentioned in this update that_
"Fixes an issue that prevented some apps from accessing photos from Photo Library"
So test your app using XCode 6 on device with iOS 8.0.2 version it will work fine
Don't test it on iOS 8.0 simulator.
This helped me, hope the same for you.
UIImagePickerController *imagePickerController= [[UIImagePickerController alloc] init];
[imagePickerController setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
// image picker needs a delegate so we can respond to its messages
[imagePickerController setDelegate:self];
self.shouldCallViewWillAppear = NO;
if(IS_IOS8)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Place image picker on the screen
[self presentViewController:imagePickerController animated:YES completion:nil];
}];
}
else
{
[self presentViewController:imagePickerController animated:YES completion:nil];
}
You can dismiss the presented view controller (if any) by using
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
This worked for me.
All you need to do is dismiss already presented ViewController:
if (self.presentedViewController) {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
[self openPhotoPicker:sourceType];
If it still produces error, put openPhotoPicker: to completion handler
I simply did this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
(unsigned long)NULL), ^(void) {
[self retractActivePopover];
dispatch_async(dispatch_get_main_queue(), ^ {
_activePopover=imagePickerPopover;
UIBarButtonItem *callingButton = (UIBarButtonItem*) sender;
[imagePickerPopover presentPopoverFromBarButtonItem:callingButton permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
});
});
On iOS 8 you should use the new API:
if (SYSTEM_VERSION_IOS_8) {
self.imagePickerController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popPC = self.imagePickerController.popoverPresentationController;
popPC.barButtonItem = self.popoverItem;
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:self.imagePickerController animated:YES completion:nil]
}
I recommend you watch the 2014 WWDC session 228 a look in side presentation controllers
I went through a lot of pain coming up with a solution which works on both iPad and iPhone, this is the final code which some of it comes from comments of other people:
the code has some bugs but it's a very good place to start :)
definitions :
__weak IBOutlet UIButton *attachButton;
UIImage *image;
button's action :
- (IBAction)doAttach:(id)sender {
UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:#"Select image from" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"From library",#"From camera", nil] ;
[action showInView:self.view];
}
#pragma mark - ActionSheet delegates
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if( buttonIndex == 1 ) {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusAuthorized)
{
NSLog(#"%#", #"You have camera access");
}
else if(authStatus == AVAuthorizationStatusDenied)
{
NSLog(#"%#", #"Denied camera access");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){
NSLog(#"Granted access to %#", AVMediaTypeVideo);
} else {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“no camera access“
message: #“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
NSLog(#"Not granted access to %#", AVMediaTypeVideo);
return ;
}
}];
}
else if(authStatus == AVAuthorizationStatusRestricted)
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“no camera access“
message: #“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
NSLog(#"%#", #"Restricted, normally won't happen");
}
else if(authStatus == AVAuthorizationStatusNotDetermined)
{
NSLog(#"%#", #"Camera access not determined. Ask for permission.");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){
NSLog(#"Granted access to %#", AVMediaTypeVideo);
} else {
NSLog(#"Not granted access to %#", AVMediaTypeVideo);
return ;
}
}];
}
else
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“No camera access“
message: #“error accusing camera”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
return;
//NSLog(#"%#", #"Camera access unknown error.");
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIImagePickerController *pickerView =[[UIImagePickerController alloc]init];
pickerView.allowsEditing = YES;
pickerView.delegate = self;
pickerView.sourceType = UIImagePickerControllerSourceTypeCamera;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];
pickerView.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popPC = pickerView.popoverPresentationController;
popPC.sourceView = attachButton;
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:pickerView animated:YES completion:nil];
} else {
[self presentModalViewController:pickerView animated:YES ];
}
}
}else if( buttonIndex == 0 ) {
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
case ALAuthorizationStatusRestricted:
case ALAuthorizationStatusDenied:
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“no access to library”
message: #“if you wish to access photos in this app go to settings -> appName-> and turn on photos .”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
break;
default:
{
UIImagePickerController *pickerView = [[UIImagePickerController alloc] init];
pickerView.allowsEditing = YES;
pickerView.delegate = self;
[pickerView setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];
pickerView.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popup = pickerView.popoverPresentationController;
popup.sourceView = attachButton;
popup.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:pickerView animated:YES completion:nil];
} else {
[self presentModalViewController:pickerView animated:YES ];
}
}
break;
}
}
}
#pragma mark - PickerDelegates
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[self dismissModalViewControllerAnimated:true];
UIImage * img = [info valueForKey:UIImagePickerControllerEditedImage];
image = img;
}
performSelector:withObject:afterDelay solved my problem.
also didDismissWithButtonIndex do the trick.
Max
Here's a Xamarin solution. What worked for me was to add my actions to a Dismissed event handler.
this.btnPhoto.TouchUpInside += (sender, e) =>
{
actionSheet = new UIActionSheet ("Add Photo");
actionSheet.AddButton ("Take Photo");
actionSheet.AddButton ("Select from Library");
actionSheet.AddButton ("Cancel");
actionSheet.DestructiveButtonIndex = -1; // red
actionSheet.CancelButtonIndex = 3; // black
actionSheet.Clicked += delegate(object a, UIButtonEventArgs b)
{
actionSheet.Dismissed += (object aSender, UIButtonEventArgs dismissArgs) =>
{
switch (dismissArgs.ButtonIndex)
{
case 0:
showCamera ();
break;
case 1:
showPhotoLibrary ();
break;
}
};
};
actionSheet.ShowInView (view);
};