Since upgrading to XCode 5/iOS 7, I'm getting the following error when calling a function which is supposed to present the Redlaser SDK barcodepickercontroller:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target .'
* First throw call stack:
(
0 CoreFoundation 0x02ef25e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x028dd8b6 objc_exception_throw + 44
2 UIKit 0x006e817a -[UIViewControllerpresentViewController:withTransition:completion:] + 4879
3 UIKit 0x006e8caf -[UIViewController presentViewController:animated:completion:] + 130
4 UIKit 0x006e8cef -[UIViewController presentModalViewController:animated:] + 56
5 Extinguishers 0x0000b703 -[LoginViewController scanPressed] + 1299
And here's my method which causes it:
-(IBAction) scanPressed
{
if (overlayController.parentPicker == nil)
{
BarcodePickerController * picker = [[BarcodePickerController alloc] init];
[picker setOverlay:overlayController];
[picker setDelegate:self];
// Initialize with portrait mode as default
picker.orientation = UIImageOrientationUp;
// The active scanning region size is set in OverlayController.m
}
// Update barcode on/off settings
[overlayController.parentPicker setScanUPCE:YES];
[overlayController.parentPicker setScanEAN8:YES];
[overlayController.parentPicker setScanEAN13:YES];
//[overlayController.parentPicker setScanSTICKY:YES];
//[overlayController.parentPicker setScanQRCODE:YES];
[overlayController.parentPicker setScanCODE128:YES];
[overlayController.parentPicker setScanCODE39:YES];
[overlayController.parentPicker setScanITF:YES];
// Data matrix decoding does not work very well so it is disabled for now
[overlayController.parentPicker setScanDATAMATRIX:NO];
// hide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES];
// Show the scanner overlay - THIS LINE CAUSES THE CRASH
[self presentModalViewController:overlayController.parentPicker animated:TRUE];
}
I've also tried upgrading to the latest version of the Redlaser SDK, and the error is still the same. I did not have this problem before switching to iOS 7 as the base SDK.
The only thing I can think of is that picker(the parent) might be going out of scope and getting deallocated. Put a test right before the buggy line to check if the parent still exists: if(overlayController.parentPicker == nil) NSLog(#"Parent is nil");
If it really is nil (like your original error is saying), try declaring picker before that first if statement.
BarcodePickerController *picker;
if(overlayController.parentPicker == nil)
{
picker = [[BarcodePickerController alloc] init];
//...
The child might only have a weak pointer to the parent, so you may need to declare the parent as a #property or somewhere where it won't be deallocated before your viewController is popped off the stack.
Related
Installed Xcode 7.1 Beta and tested my app on iOS 9.0 and got below error. I went thorough different questions here.
I am using IIViewDeckController for left menu and PullRefreshTableViewController. In app delegate I register to different notification and give webservice call to get data for view controllers of VC1(Menu1) and VC2(Menu2), both inherits PullRefreshTableViewController. VC1 is displayed at first. When user navigates to VC2 the view gets loaded with data pulled but crashes with below exception.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7fa8c541eaf0 of class UIView was deallocated while key value observers were still registered with it. Current observation info: (
Context: 0x0, Property: 0x7fa8c1d1b470>
)'
*** First throw call stack:
(
0 CoreFoundation 0x0000000110d7df65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001107f5deb objc_exception_throw + 48
2 CoreFoundation 0x0000000110d7de9d +[NSException raise:format:] + 205
3 Foundation 0x000000010f6528c1 NSKVODeallocate + 294
4 libobjc.A.dylib 0x000000011080a0b8 _ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv + 488
5 CoreFoundation 0x0000000110c6b956 _CFAutoreleasePoolPop + 22
6 CoreFoundation 0x0000000110c9f8d1 __CFRunLoopRun + 2081
7 CoreFoundation 0x0000000110c9ee28 CFRunLoopRunSpecific + 488
8 GraphicsServices 0x00000001134e4ad2 GSEventRunModal + 161
9 UIKit 0x000000010e12eca1 UIApplicationMain + 171
10 SeeMyRadiology 0x000000010d0d507e SeeMyRadiology + 16510
11 libdyld.dylib 0x000000011126992d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
**NOTE:**Same code works on iPad without error
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard* mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle: nil];
UIViewController* menuController = [mainStoryboard instantiateViewControllerWithIdentifier:#"LeftSideMenu"];
UINavigationController* navigationController = (UINavigationController *) self.window.rootViewController;
self.viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:navigationController leftViewController:menuController rightViewController:nil];
self.window.rootViewController = self.viewDeckController;
}
OR
https://github.com/edgecase/ECSlidingViewController
Just in case unable to solve problem.
If your table is reloaded it's possible that you loose your views, I mean, they are deallocated. If there are some connections beetwen deallocated views and values somewhere it causes the crash. You need to stop observing values before deallocating in order to avoid crash. Check this scenerio.
This worked for me.
The problem was while pushing view over the IIViewDeckController.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UINavigationController *centerController = [[UINavigationController alloc] initWithRootViewController:appDelegate.viewController];
[appDelegate.viewDeckController closeLeftViewBouncing:^(IIViewDeckController *controller)
{
appDelegate.viewDeckController.centerController = centerController;
}];
Thank you your input guys. :)
I have a situation where I am trying to resolve these Crashlytics issues and I have this crash log
Thread : Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x34217f46 objc_msgSend + 5
1 UIKit 0x29a2d5a3 -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 182
2 CoreFoundation 0x2630cad4 __invoking___ + 68
3 CoreFoundation 0x26239645 -[NSInvocation invoke] + 300
4 CoreFoundation 0x2623d0c7 -[NSInvocation invokeWithTarget:] + 50
5 WebKitLegacy 0x326d9261 -[_WebSafeForwarder forwardInvocation:] + 224
6 CoreFoundation 0x2630b62f ___forwarding___ + 354
7 CoreFoundation 0x2623d008 _CF_forwarding_prep_0 + 24
8 CoreFoundation 0x2630cad4 __invoking___ + 68
9 CoreFoundation 0x26239645 -[NSInvocation invoke] + 300
10 WebCore 0x31c02729 HandleDelegateSource(void*) + 100
11 CoreFoundation 0x262cefbf __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14
12 CoreFoundation 0x262ce461 __CFRunLoopDoSources0 + 364
13 CoreFoundation 0x262cca35 __CFRunLoopRun + 772
14 CoreFoundation 0x2621a3b1 CFRunLoopRunSpecific + 476
15 CoreFoundation 0x2621a1c3 CFRunLoopRunInMode + 106
16 GraphicsServices 0x2d801201 GSEventRunModal + 136
17 UIKit 0x2988443d UIApplicationMain + 1440
18 abc 0x0030dcd7 main (main.m:14)
I can understand that its some callback on webview delegate and bad excess has occurred, so to rectify this I handled the delegates via
[self.webview stopLoading];
self.webview.delegate =nil;
in all the classes, yet I can see this crash. Can you enlighten me what's possibly going wrong and some approach to rectify this?
The following might be the case here
The user is presented a screen with UIWebView
The UIViewController sets self as the delegate Web page starts downloading
The User quits screen
UIViewController gets deallocated UIWebView finishes loading and sends I am finished loading message to its delegate
or
some other delegate method gets called when the webview object is no more.i.e dangling pointer effect
1.Always make sure you stop loading the webView and remove the delegate before leaving the view
Before releasing an instance of UIWebView for which you have set a
delegate, you must first set its delegate property to nil. This can
be done, in your dealloc method
Here is the reference
// If ARC is used
- (void)dealloc {
[_webView setDelegate:nil];
[_webView stopLoading];
}
// If ARC is not used
- (void)dealloc {
[webView setDelegate:nil];
[webView stopLoading];
[webView release];
[super dealloc];
}
// ARC - Before iOS6 as its deprecated from it.
- (void)viewWillUnload {
[webView setDelegate:nil];
[webView stopLoading];
}
2.Make sure you are not stopLoading and setDelegate to nil in viewWillDisappear
if the ViewController is a child of a another ViewController, u can
trigger the removal of the ViewController's view from the parent
ViewController's view with an animation. At the same time, u can
remove the ViewController from its parent and nil out its reference.
at this point ViewController will be nil and viewWillDisappear
will never be called, meaning the WebView delegate will never be
cleaned up
Use dealloc and ensure that your WebView is always cleaned up.
3.Make sure you set the ContentOffset of the subviews of webview to CGPointZero without animation
In iPad in some versions while webview is scrolling if you close the parent
viewcontroller without setting ContentOffset to CGPointZero this
kind of problems will come
so its better to you call the following code of in parent viewcontroller before closing it
for (id subview in webView.subviews){
if ([[subview class] isSubclassOfClass: [UIScrollView class]]){
[subview setContentOffset:CGPointZero animated:NO];
}
}
Hope this helps.Feel free to ask your doubts.
4.Generally speaking You should not embed UIWebView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.
Here is the reference
Try disabling your UIWebView's scrolling behaviour before the ViewController deallocs it
for (id subview in webView.subviews){
if ([[subview class] isSubclassOfClass: [UIScrollView class]]){
[subview setContentOffset:CGPointZero animated:NO];
}
}
p.s. Dipen Chudasama's approach is correct, according to Apple's documentation, you should really set the delegate property to nil before releasing the webview, assuming you have released the webview correctly inside dealloc function but not viewWillDisappear
UIWebViews delegate uses assign and not weak. So you need to nullify the delegate when the webView's controller gets deallocated.
Example:
- (void)dealloc
{
self.webview.delegate =nil;
}
Are you adding a web view within your subclass of a web view? Generally that's the problem and if so, changing the superclass to a UIView would solve the problem.
Use visa versa means first nil your delegate and then after stop loading web view may be help you.
like this.
[_webView setDelegate:nil];
[_webView stopLoading];
As per apple document : Important Before releasing an instance of UIWebView for which you have set a delegate, you must first set its delegate property to nil.
Use [listener use] instead, to tell your UIWebView to handle clicked URL.
-(void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id )listener
{
[listener use]
}
I'm having a weird issue with UIViews and manual memory management.
I have a view (contentView) which is the main view of a view controller.
After a long press on the contentView, another view is supposed to fade in (on top of it).
When the gestures ends, the additional view fades out.
The issue is:
When the contentView receives a long press, I create the auxiliary view, add it to the contentView, and then release it, which is/was the common practice back in the pre-ARC days.
It works okay on the iPhone, but it crashes on the iPad!
The crashy line is:
[ZPNowPlayingItemInfoView dealloc]
...which gets triggered when I remove the auxiliary view from the contentView.
Any clues on why this happens?
If I comment out the release line (see my comment in the code), it works flawlessly on both devices, but it feels bad.
Here's the code:
-(void)longPressDetected:(UILongPressGestureRecognizer*)longPressGR
{
//Content view of the view controller I'm in
UIView *contentView = MSHookIvar<UIView*>(self, "_contentView");
if (longPressGR.state == UIGestureRecognizerStateBegan) {
id item = MSHookIvar<MPAVItem*>(self, "_item");
ZPNowPlayingItemInfoView *infoView =
[[ZPNowPlayingItemInfoView alloc] initWithFrame:
CGRectMake(0,0,contentView.frame.size.width,contentView.frame.size.height)
item:item];
//infoView retain count: 1
[infoView setAlpha:0.f];
[contentView addSubview:infoView];
//infoView retain count: 3 (???)
//iPad goes berserk on this line
//Commented - Works both on iPhone and iPad
//Uncommented - Works only on iPhone
//[infoView release];
//infoView retain count: 2 (if release is uncommented)
[UIView animateWithDuration:0.35f animations:^{
[infoView setAlpha:1.0f];
} completion:^(BOOL finished) {
//infoView retain count: 3
}];
} else if (longPressGR.state == UIGestureRecognizerStateEnded) {
ZPNowPlayingItemInfoView* infoView = nil;
for (UIView *subview in contentView.subviews) {
if ([subview isKindOfClass:[ZPNowPlayingItemInfoView class]]) {
infoView = (ZPNowPlayingItemInfoView*)subview;
break;
}
}
[UIView animateWithDuration:0.35f animations:^{
[infoView setAlpha:0.f];
} completion: ^(BOOL finished){
[infoView removeFromSuperview];
}];
}
P.S. I need to use manual memory management. This is a tweak for jailbroken devices.
Stack trace:
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x195287bdc 0x19526c000 + 0x1bbdc // objc_msgSend + 0x1c
1 + Musix.dylib 0x10015b19c 0x100154000 + 0x719c // -[ZPNowPlayingItemInfoView dealloc] + 0x48
2 libsystem_blocks.dylib 0x19590d90c 0x19590c000 + 0x190c // _Block_release + 0xfc
3 UIKit 0x188ef8590 0x188eb0000 + 0x48590 // -[UIViewAnimationBlockDelegate dealloc] + 0x44
4 CoreFoundation 0x1845f1374 0x1845ec000 + 0x5374 // CFRelease + 0x208
5 CoreFoundation 0x184601004 0x1845ec000 + 0x15004 // -[__NSDictionaryI dealloc] + 0x8c
6 libobjc.A.dylib 0x19528d720 0x19526c000 + 0x21720 // (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 0x230
7 CoreFoundation 0x1845f4f90 0x1845ec000 + 0x8f90 // _CFAutoreleasePoolPop + 0x18
8 CoreFoundation 0x1846c774c 0x1845ec000 + 0xdb74c // __CFRunLoopRun + 0x5d8
9 CoreFoundation 0x1845f51f0 0x1845ec000 + 0x91f0 // CFRunLoopRunSpecific + 0x188
10 GraphicsServices 0x18d7575a0 0x18d74c000 + 0xb5a0 // GSEventRunModal + 0xa4
11 UIKit 0x188f26780 0x188eb0000 + 0x76780 // UIApplicationMain + 0x5cc
12 Music (*) 0x10006ee28 0x100064000 + 0xae28 // 0x0000adac + 0x7c
13 libdyld.dylib 0x1958e2a04 0x1958e0000 + 0x2a04 // start + 0x0
ZPNowPlayingItemInfoView:
#interface ZPNowPlayingItemInfoView()
#property (nonatomic, retain) MPAVItem* item;
#property (nonatomic, retain) MPUSlantedTextPlaceholderArtworkView *artworkView;
#property (nonatomic, retain) UILabel *artistLabel;
#property (nonatomic, retain) UILabel *albumLabel;
#property (nonatomic, retain) UILabel *songLabel;
#end
ZPNowPlayingItemInfoView dealloc:
-(void)dealloc
{
[super dealloc];
[self.item release];
[self.artworkView release];
[self.artistLabel release];
[self.songLabel release];
}
You have some problem in ZPNowPlayingItemInfoView class. When this problem happens? Only when the object gets deallocated. When you comment [infoView release] out, your object is never deallocated and the problem doesn't arise - you will have a memory leak though.
Inspect what ZPNowPlayingItemInfoView does, especially its dealloc method. Are you sure you are constructing it correctly? Is item always a valid object?
After seeing the ZPNowPlayingItemInfoView dealloc method, the problem is quite clear - [super dealloc] must always be the last call, not the first one. Once you have deallocated the object, accessing its properties is an undefined operation.
When commenting out the release is a working workaround, that indicates that you have released it once too often. It may well be the very one release that you commented out.
removeFromSuperview does reduce the retain count by 1.
I suggest re-visiting the full life cycle of the view object. This can be tricky though. Each retain needs to have exactly one corresponding release or autorelease. Assigning the view to a property using its getter (self.myView = subview) does retain it and re-assigning another view to the property (self.myView = someOhterview) releases subview.
On the contrary accessing the iVar directly (myView = subview) does not maintain the release/retain-cycle.
There is more than that. Adding the view and removing it from an array, set or dictionary will change the retain count accordingly.
So go and have a deeper look at it. Use instruments to observe the retain count.
I have two methods that toggle the right bar button items in a view controller's UINavigationItem. It's basically to show a search bar in the navigation bar when the search button is tapped, and to hide the search bar when the user executes a search
- (void)displaySearchUI
{
[self.mainNavigationController.topViewController.navigationItem setRightBarButtonItems:[self searchOpenItems] animated:YES];
[self.searchBar becomeFirstResponder];
}
- (void)dismissSearchUI
{
[self.mainNavigationController.topViewController.navigationItem setRightBarButtonItems:[self searchClosedItems] animated:YES];
}
- (NSArray *)searchClosedItems
{
return #[[self someCustomItem],
[self someOtherItem],
[self searchButtonItem],
];
}
- (NSArray *)searchOpenItems
{
return #[[self someCustomItem],
[self someOtherItem],
[self searchBarItem],
];
}
the item returned from searchButtonItem uses a UIBarButtonItem with an image, while the item returned from searchBarItem has a custom view of a UISearchBar. the other items in each are identical in each search state.
When I call displaySearchUI, the searchbar becoming the first responder opens a popover to show some search suggestions. When the popover is dismissed by the user, dismissSearchUI is called via the popoverControllerDidDismissPopover: delegate method. However at that point, often the app encounters a crash within UINavigationBar:
-[CALayer enumerateObjectsUsingBlock:]: unrecognized selector sent to instance 0x7de9ac80
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CALayer enumerateObjectsUsingBlock:]: unrecognized selector sent to instance 0x7de9ac80'
*** First throw call stack:
(
0 CoreFoundation 0x056f0946 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x05379a97 objc_exception_throw + 44
2 CoreFoundation 0x056f85c5 -[NSObject(NSObject) doesNotRecognizeSelector:] + 277
3 CoreFoundation 0x056413e7 ___forwarding___ + 1047
4 CoreFoundation 0x05640fae _CF_forwarding_prep_0 + 14
5 UIKit 0x03ba38aa -[UINavigationBar _setLeftViews:rightViews:] + 3774
6 UIKit 0x03b8f77e -[UINavigationItem updateNavigationBarButtonsAnimated:] + 186
7 UIKit 0x03b901a0 -[UINavigationItem setObject:forLeftRightKeyPath:animated:] + 600
8 UIKit 0x03b9100a -[UINavigationItem setRightBarButtonItems:animated:] + 104
9 MyApp 0x0028088b -[DisplayManager dismissSearchUI] + 283
I'm not sure exactly what could be happening here. It seems to happen whether or not setting the items is animated. It also only happens when the user taps outside the popover. If I programmatically dismiss the popover and call dismissSearchUI, there's no crash (I imagine due to the different order in which the animations occur, or due to some state differences in the UI when the user dismisses a popover vs a programmatic dismissal. I've tried to work around it by doing this:
#pragma mark - UIPopoverControllerDelegate
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
[self dismissSearchSuggestionsUI];
return NO;
}
- (void)dismissSearchSuggestionsUI
{
[self.popoverController dismissPopoverAnimated:YES];
[self.displayManager dismissSearchUI];
}
But I get an EXC_BAD_ACCESS crash instead here, (with a similar stack trace that leads me to believe it's the same issue, just a different symptom due to timing).
Has anyone encountered something like this, and is there a way to work around this without having to disable manual user popover dismissals altogether?
Bah, i figured it out right after posting. By ammending dismissSearchUI's method to do this:
- (void)dismissSearchUI
{
[self.searchBar resignFirstResponder]
[self.mainNavigationController.topViewController.navigationItem setRightBarButtonItems:[self searchClosedItems] animated:YES];
}
I resolved the issue. I figured that the search bar would resign its own first responder when the user executed a search, but that doesn't happen automatically when the user manually cancels the search which causes the bar button item it's in to be removed from the nav bar.
The setContentViewController method in UIPopoverController seems to be causing an app crash in iOS 8. Just wondering if anybody else also faced this issue in iOS 8. This works without any issue in iOS 7.
The error pointed in the exception seems to be misleading as it states that the setContentViewController should be called after presenting the popover
- (void)buttonPressed {
UIViewController *tableViewController = [UIViewController new];
if(_popover == nil){
_popover = [[UIPopoverController alloc] initWithContentViewController:tableViewController];
[_popover presentPopoverFromRect:CGRectMake(self.textField.frame.size.width / 2, self.textField.frame.size.height / 1, 1, 1) inView:self.textField permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}else{
[_popover setContentViewController:tableViewController];
}
}
Here is Stack trace from the crash,
2014-09-11 16:48:39.904 iOS 8 Rotation[3969:67869] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIPopoverController setContentViewController:animated:] can only be called after the popover has been presented.'
*** First throw call stack:
(
0 CoreFoundation 0x01c79df6 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x01903a97 objc_exception_throw + 44
2 CoreFoundation 0x01c79d1d +[NSException raise:format:] + 141
3 UIKit 0x00b1946f -[UIPopoverPresentationController _setContentViewController:animated:] + 89
4 UIKit 0x009bb1b4 -[UIPopoverController setContentViewController:animated:] + 155
5 UIKit 0x009bb114 -[UIPopoverController setContentViewController:] + 48
6 iOS 8 Rotation 0x00046ca5 -[MianViewController buttonPressed] + 933
7 libobjc.A.dylib 0x019197cd -[NSObject performSelector:withObject:withObject:] + 84
8 UIKit 0x002ef79d -[UIApplication sendAction:to:from:forEvent:] + 99
9 UIKit 0x002ef72f -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64
10 UIKit 0x00422a16 -[UIControl sendAction:to:forEvent:] + 69
11 UIKit 0x00422e33 -[UIControl _sendActionsForEvents:withEvent:] + 598
12 UIKit 0x0042209d -[UIControl touchesEnded:withEvent:] + 660
13 UIKit 0x0033faba -[UIWindow _sendTouchesForEvent:] + 874
14 UIKit 0x00340595 -[UIWindow sendEvent:] + 791
15 UIKit 0x00305aa9 -[UIApplication sendEvent:] + 242
16 UIKit 0x003158de _UIApplicationHandleEventFromQueueEvent + 20690
17 UIKit 0x002ea079 _UIApplicationHandleEventQueue + 2206
18 CoreFoundation 0x01b9d7bf __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
19 CoreFoundation 0x01b932cd __CFRunLoopDoSources0 + 253
20 CoreFoundation 0x01b92828 __CFRunLoopRun + 952
21 CoreFoundation 0x01b921ab CFRunLoopRunSpecific + 443
22 CoreFoundation 0x01b91fdb CFRunLoopRunInMode + 123
23 GraphicsServices 0x040cc24f GSEventRunModal + 192
24 GraphicsServices 0x040cc08c GSEventRun + 104
25 UIKit 0x002ede16 UIApplicationMain + 1526
26 iOS 8 Rotation 0x0004774d main + 141
27 libdyld.dylib 0x0224cac9 start + 1
28 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
I just encountered this same error testing our app under iOS 8. In our case, I took the error message at face value and changed a pattern we had in a few places.
The pattern we had to change was:
(1) in our view controller's init, instantiate a popover controller instance.
(2) on some event, set the popover controller's contentViewController property to the desired vc.
(3) call presentPopoverFromRect on the popover controller
and we simply changed step (2) to re-instantiate the popover controller with the desired content vc as an init parameter and ceased setting the contentViewController property (as we're always doing it prior to presenting the popover).
I was experiencing this same issue and finally solved it.
I have two buttons, each one shows its own popover. I was reusing the same UIPopoverController to show both of them. The first click worked fine, but then if you clicked the other one the app crashed.
The way I solved it is create a new UIPopoverController on each click:
importImagePickerControlPopoverController=[[UIPopoverController alloc] initWithContentViewController:pickerController];
[importImagePickerControlPopoverController setDelegate:self];
switch(pickerType)
{
case UIImagePickerControllerSourceTypePhotoLibrary:
case UIImagePickerControllerSourceTypeSavedPhotosAlbum:
[importImagePickerControlPopoverController setPopoverContentSize:CGSizeMake(320, 300) animated:YES];
break;
case UIImagePickerControllerSourceTypeCamera:
[importImagePickerControlPopoverController setPopoverContentSize:CGSizeMake(640, 640) animated:YES];
break;
}
[importImagePickerControlPopoverController setContentViewController:pickerController];
Similar to #user3495742 solution:
-(void)testAndSetPopoverWithVc:(UIViewController*)vc {
if (popover4Menu) {
if ([popover4Menu isPopoverVisible]) {
[popover4Menu setContentViewController:vc animated:YES];
return;
} else {
popover4Menu=nil;
}
};
popover4Menu=[[UIPopoverController alloc] initWithContentViewController:vc];
popover4Menu.delegate=self;
}
Problem rises when reassigning a view controller to an existing popover.
Free and realloc popover before assigning new content view controller: this fixed for me.
I had the same issue and this is what fixed it for me.
Try This
- (void)buttonPressed{
UIViewController *tableViewController = [UIViewController new];
//Check if the popover is nil or not visible
if(_popover == nil || _popover.popoverVisible == false){
_popover = [[UIPopoverController alloc] initWithContentViewController:tableViewController];
[_popover presentPopoverFromRect:CGRectMake(self.textField.frame.size.width / 2, self.textField.frame.size.height / 1, 1, 1) inView:self.textField permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}else{
[_popover setContentViewController:tableViewController];
}
}
You have already have the content view controller set:
_popover = [[UIPopoverController alloc] initWithContentViewController:tableViewController];
↑
Here
So, why not just delete the line?:
[_popover setContentViewController:tableViewController];
That should work.
If popover is not visible when you are calling [_popover setContentViewController:tableViewController];, app will get crash.
Because this method should be called when popover is visible on the screen.
Make sure your popover is visible,
if(_popover != nil && [_popover isPopoverVisible] == YES)
{
[_popover setContentViewController:tableViewController];
}else
{
//create new popover object if _popover is nil or present it
}
[self.popover dismissPopoverAnimated:YES]; //in case it's already showing.
self.popover = nil; // N.B. this is not the same as popover = nil.
self.popover = [[UIPopoverController alloc] initWithContentViewController:tableViewController];
[self.popover presentPopoverFromRect:CGRectMake(self.textField.frame.size.width /
2, self.textField.frame.size.height / 1, 1, 1) inView:self.textField
permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
You do not need to create new instance of UIPopoverController neither set new contentViewController property after you first present UIPopoverViewController. (it depends on how you dismiss you popoverController)
However contentViewController can't be changed before popoverController presentation.
To workaround check popoverController.contentViewController properties. If it is nil, set conntentViewController, otherwise just present popover.
If you want to change contentViewController do it after presentation: use setContentViewController:animated: method.
Check that popoverController.isPopoverVisible before call this method.
Add these two methods into your UIwebview main class.
add <UIPopoverPresentationControllerDelegate> in your webview interface.h class as well.
define .
#property (strong, nonatomic) UIPopoverPresentationController *pop;
then
#synthesize pop;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Assuming you've hooked this all up in a Storyboard with a popover presentation style
if ([segue.identifier isEqualToString:#"showPopover"]) {
UINavigationController *destNav = segue.destinationViewController;
pop = destNav.viewControllers.firstObject;
// This is the important part
UIPopoverPresentationController *popPC = destNav.popoverPresentationController;
popPC.delegate = self;
}
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}