Pushing A View Controller Crashes The App - ios

Here's the scenario: I am using MWPhotoBrowser. I can push it fine once. The second time I try to push it the app crashes with nothing helpful. This is an ARC project, and this exact same code works fine in previous versions of the app. I am dumbfounded.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
selectedIndexPath = indexPath;
if(browser == nil)
{
browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
}
// Set options
browser.displayActionButton = YES; // Show action button to allow sharing, copying, etc (defaults to YES)
browser.displayNavArrows = YES; // Whether to display left and right nav arrows on toolbar (defaults to NO)
browser.zoomPhotosToFill = NO; // Images that almost fill the screen will be initially zoomed to fill (defaults to YES)
[browser setCurrentPhotoIndex:indexPath.row]; // Example: allows second image to be presented first
//browser.wantsFullScreenLayout = YES; // iOS 5 & 6 only: Decide if you want the photo browser full screen, i.e. whether the status bar is affected (defaults to YES)
// Present
[self.navigationController pushViewController:browser animated:YES];
}
Tap a cell once, MWPhotoBrowser opens fine. Go back, tap a cell again, the app crashes just with the debugger but no call stack or error reason:
(lldb):
browser is a strong member variable. It isn't being deallocated prematurely. I can also guarantee it is crashing exactly on the last line of the method.
Can someone please enlighten me on this? I'd solve it if the app at least gave me a reason for the crash and not just throw the debugger on my face.

I have used MWPhotoBrowser extensively and ran across the same problem once. The way I solved it was by checking the MWPhoto objects to see if they actually had been set properly. I realised that I had not created some of them, hence the crash. I would check the place where you store your MWPhotos and make sure they are all set. Hope this helps!

Related

MPPlayableContentDataSource called inconsistently

I am working on implementing support for a CarPlay audio app, and am attempting to display listings in the simulator. I have implemented MPPlayableContentDataSource, but find that it is called inconsistently. It is called the first time the app is launched on a simulator, and if CarPlay is open on launch, I can make the first item display by scrolling up an otherwise empty listing to trigger a redraw.
CarPlay does not seem able to call the data source, however, and on a subsequent launch I see an empty screen or a spinner followed by the message Unable to connect to "AppName". I have tried different things but the main points are as follows:
In application: didFinishLaunchingWithOptions:
self.contentDataSource = [[MYContentDataSource alloc] init];
self.contentDelegate = [[MYContentDelegate alloc] init];
MPPlayableContentManager *contentManager = [MPPlayableContentManager sharedContentManager];
contentManager.dataSource = self.contentDataSource;
contentManager.delegate = self.contentDelegate;
[contentManager beginUpdates];
[contentManager endUpdates];
I've played around with beginUpdates endUpdates and reloadData methods of the content manager, but none of these result in the content datasource actually being called.
I've implemented numberOfChildItemsAtIndexPath and contentItemAtIndexPath in the datasource, which appear to be called correctly, although only on the first launch of the app on a fresh simulator.
The main points:
- (NSInteger)numberOfChildItemsAtIndexPath:(NSIndexPath *)indexPath {
return 3;
}
- (MPContentItem *)contentItemAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger categoryId = [indexPath indexAtPosition:0];
MPContentItem *contentItem = [[MPContentItem alloc] initWithIdentifier:[NSString stringWithFormat:#"CAT-%lu", (unsigned long)categoryId]];
contentItem.title = [NSString stringWithFormat:#"Category %lu", (unsigned long)categoryId];
contentItem.subtitle = #"Subtitle";
contentItem.playable = NO;
contentItem.container = YES;
}
I've also tried retaining (or not) the reference to the MPPlayableContentManager.
I have the same behavior on an actual head unit. Any help would be appreciated.
After banging my head against the wall for quite a while, I got the following answer from Apple. Turns out that MPRemoteCommandCenter and MPNowPlayingInfoCenter are needed for CarPlay to work.
1. Start responding to MPRemoteCommandCenter events at app launch
2. Set the MPNowPlayingInfoCenter dictionary at app launch
These are required for MPPlayableContentDataSource to function correctly.
They are mentioned in the doc, but it isn't clear that they are needed for the catalog display to work. That solved the problem.

iMessageExt app Error starting application

I created my iMessage extension, when I try to open it, the first screen appears but it is totally frozen, and it does not react in any way.
I've put logs in the viewDidLoad of that first view and nothing appears there, after a few seconds I can already see those logs.
To make the application freezing lose that status, user has to slide screen left or right and back again.
I've tried looking all over the web for someone who happens to be the same, but I could not find anything.
It does not come to mind more screenshots or portions of code add, if you think I should provide some additional information, just let me know
Any help would be appreciated.
Thank you.
UPDATE:
This is my Project Structure.
This is my viewDidLoad code.
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"here viewDidLoad iMessage ext~~~!");
[self applyCornerRadiusToBtn];
[self registerPresentationAction];
NSDictionary *user = [self getUserInfoFromHostApp];
if (user) {
NSLog(#"Here != null user info");
//It is assumed that when you enter this point and run this log, the app should navigate to the next screen, but it does not.
[self performSegueWithIdentifier:#"goToYoutubeListIm" sender:nil];
} else {
NSLog(#"Here userInfo null");
}
}
- (NSDictionary *)getUserInfoFromHostApp
{
NSUserDefaults *myDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.xxxxx"];
NSDictionary *userNameSaved = [myDefaults objectForKey:#"userInfoExt"];;
NSLog(#"userNameSaved in xxxx Ext ==> %#",userNameSaved);
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.com.xxxx"];
NSLog(#"groupURL ==> %#",groupURL);
return userNameSaved;
}
For all concerned I have found the problem or problems to be accurate.
1) I was creating my controllers type MSMessagesAppViewController. Apparently there should only be one controller of this type.
2) I had logic in the viewDidAppear in my MSMessagesAppViewController. For some strange reason this also caused the problem, I had to get the logic out there and force the user to interact with a button to execute the logic that was in the didAppear

Controlling the screenshot in the iOS 7 multitasking switcher

I've been trying to find some information regarding the new multitasking switcher in iOS 7 and especially the screenshot that the OS takes when the app is going into hibernation.
Is there any way to completely turn off this feature or screenshot? Or can I hide the app altogether from the switcher? The app needs to run in the background, but we do not want to show any screenshot from the app.
The screenshot is potentially a security-risk, think along the lines for banking-apps where your card number or account summary will be available to anyone that double-click on the home button on the device.
Anyone with any insight into this? Thanks.
In Preparing Your UI to Run in the Background, Apple says:
Prepare Your UI for the App Snapshot
At some point after your app enters the background and your delegate method returns, UIKit takes a snapshot of your app’s current user interface. The system displays the resulting image in the app switcher. It also displays the image temporarily when bringing your app back to the foreground.
Your app’s UI must not contain any sensitive user information, such as passwords or credit card numbers. If your interface contains such information, remove it from your views when entering the background. Also, dismiss alerts, temporary interfaces, and system view controllers that obscure your app’s content. The snapshot represents your app’s interface and should be recognizable to users. When your app returns to the foreground, you can restore data and views as appropriate.
See Technical Q&A QA1838: Preventing Sensitive Information From Appearing In The Task Switcher
In addition to obscuring/replacing sensitive information, you might also want to tell iOS 7 to not take the screen snapshot via ignoreSnapshotOnNextApplicationLaunch, whose documentation says:
If you feel that the snapshot cannot correctly reflect your app’s user interface when your app is relaunched, you can call ignoreSnapshotOnNextApplicationLaunch to prevent that snapshot image from being taken.
Having said that, it appears that the screen snapshot is still taken and I have therefore filed a bug report. But you should test further and see if using this setting helps.
If this was an enterprise app, you might also want to look into the appropriate setting of allowScreenShot outlined in the Restrictions Payload section of the Configuration Profile Reference.
Here is an implementation that achieves what I needed. You can present your own UIImageView, or your can use a delegate-protocol pattern to obscure the confidential information:
// SecureDelegate.h
#import <Foundation/Foundation.h>
#protocol SecureDelegate <NSObject>
- (void)hide:(id)object;
- (void)show:(id)object;
#end
I then gave my app delegate a property for that:
#property (weak, nonatomic) id<SecureDelegate> secureDelegate;
My view controller sets it:
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
delegate.secureDelegate = self;
}
The view controller obviously implements that protocol:
- (void)hide:(id)object
{
self.passwordLabel.alpha = 0.0;
}
- (void)show:(id)object
{
self.passwordLabel.alpha = 1.0;
}
And, finally, my app delegate avails itself of this protocol and property:
- (void)applicationWillResignActive:(UIApplication *)application
{
[application ignoreSnapshotOnNextApplicationLaunch]; // this doesn't appear to work, whether called here or `didFinishLaunchingWithOptions`, but seems prudent to include it
[self.secureDelegate hide:#"applicationWillResignActive:"]; // you don't need to pass the "object", but it was useful during my testing...
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self.secureDelegate show:#"applicationDidBecomeActive:"];
}
Note, I'm using applicationWillResignActive rather than the advised applicationDidEnterBackground, because, as others have pointed out, the latter is not called when double tapping on the home button while the app is running.
I wish I could use notifications to handle all of this, rather than the delegate-protocol pattern, but in my limited testing, the notifications aren't handled in a timely-enough manner, but the above pattern works fine.
This is the solution I worked with for my application:
As Tommy said: You can use the applicationWillResignActive. What I did was making a UIImageView with my SplashImage and add it as subview to my main window-
(void)applicationWillResignActive:(UIApplication *)application
{
imageView = [[UIImageView alloc]initWithFrame:[self.window frame]];
[imageView setImage:[UIImage imageNamed:#"Portrait(768x1024).png"]];
[self.window addSubview:imageView];
}
I used this method instead of applicationDidEnterBackground because applicationDidEnterBackground won't be triggered if you doubletap the home button, and applicationWillResignActive will be. I heard people say though it can be triggered in other cases aswell, so I'm still testing around to see if it gives problem, but none so far! ;)
Here to remove the imageview:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(imageView != nil) {
[imageView removeFromSuperview];
imageView = nil;
}
}
Hope this helps!
Sidenote: I tested this on both the simulator and a real device: It Won't Show on the simulator, but it does on a real device!
This quick and easy method will yield a black snapshot above your app's icon in the iOS7 or later app switcher.
First, take your app's key window (typically setup in AppDelegate.m in application:didFinishLaunchingWithOptions), and hide it when your app is about to move into the background:
- (void)applicationWillResignActive:(UIApplication *)application
{
if(isIOS7Or8)
{
self.window.hidden = YES;
}
}
Then, un-hide your app's key window when your app becomes active again:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(isIOS7Or8)
{
self.window.hidden = NO;
}
}
At this point, check out the app switcher and verify that you see a black snapshot above your app's icon. I've noticed that if you launch the app switcher immediately after moving your app into the background, there can be a delay of ~5 seconds where you'll see a snapshot of your app (the one you want to hide!), after which it transitions to an all-black snapshot. I'm not sure what's up with the delay; if anyone has any suggestions, please chime in.
If you want a color other than black in the switcher, you could do something like this by adding a subview with any background color you'd like:
- (void)applicationWillResignActive:(UIApplication *)application
{
if(isIOS7Or8)
{
UIView *colorView = [[[UIView alloc] initWithFrame:self.window.frame] autorelease];
colorView.tag = 9999;
colorView.backgroundColor = [UIColor purpleColor];
[self.window addSubview:colorView];
[self.window bringSubviewToFront:colorView];
}
}
Then, remove this color subview when your app becomes active again:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(isIOS7Or8)
{
UIView *colorView = [self.window viewWithTag:9999];
[colorView removeFromSuperview];
}
}
I used the following solution:
when application is going to resign I get appWindow snapshot as a View and add blur to it. Then I add this view to app window
how to do this:
in appDelegate just before implementation add line:
static const int kNVSBlurViewTag = 198490;//or wherever number you like
add this methods:
- (void)nvs_blurPresentedView
{
if ([self.window viewWithTag:kNVSBlurViewTag]){
return;
}
[self.window addSubview:[self p_blurView]];
}
- (void)nvs_unblurPresentedView
{
[[self.window viewWithTag:kNVSBlurViewTag] removeFromSuperview];
}
#pragma mark - Private
- (UIView *)p_blurView
{
UIView *snapshot = [self.window snapshotViewAfterScreenUpdates:NO];
UIView *blurView = nil;
if ([UIVisualEffectView class]){
UIVisualEffectView *aView = [[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
blurView = aView;
blurView.frame = snapshot.bounds;
[snapshot addSubview:aView];
}
else {
UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:snapshot.bounds];
toolBar.barStyle = UIBarStyleBlackTranslucent;
[snapshot addSubview:toolBar];
}
snapshot.tag = kNVSBlurViewTag;
return snapshot;
}
make your appDelegate implementation be the as follows:
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
//...
//your code
//...
[self nvs_blurPresentedView];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
//...
//your code
//...
[self nvs_unblurPresentedView];
}
I created Example projects in Swift and Objective C.
Both projects makes the following actions in:
-application:didResignActive - snapshot is created, blurred and added to app window
-application:willBecomeActive blur view is being removed from window.
How to use:
Objecitve C
Add AppDelegate+NVSBlurAppScreen .h and .m files to your project
in your -applicationWillResignActive: method add the following line:
[self nvs_blurPresentedView];
in your -applicationDidEnterBackground: method add the following line:
[self nvs_unblurPresentedView];
Swift
add AppDelegateExtention.swift file to your project
in your applicationWillResignActive function add the following line:
blurPresentedView()
in your applicationDidBecomeActive function add the following line:
unblurPresentedView()
if only use [self.window addSubview:imageView]; in applicationWillResignActive function, This imageView won't cover UIAlertView, UIActionSheet or MFMailComposeViewController...
Best solution is
- (void)applicationWillResignActive:(UIApplication *)application
{
UIWindow *mainWindow = [[[UIApplication sharedApplication] windows] lastObject];
[mainWindow addSubview:imageView];
}
Providing my own solution as an "answers", though this solution is very unreliable. Sometimes i get a black screen as the screenshot, sometimes the XIB and sometimes a screenshot from the app itself. Depending on device and/or if i run this in the simulator.
Please note i cannot provide any code for this solution since it's a lot of app-specific details in there. But this should explain the basic gist of my solution.
In AppDelegate.m under applicationWillResignActive i check if we're
running iOS7, if we do i load a new view which is empty with the
app-logo in the middle. Once applicationDidBecomeActive is called i
re-launch my old views, which will be reset - but that works for the
type of application i'm developing.
You can use activator to configure double clicking of home button to launch multitasking and disable default double clicking of home button and launching of multitasking window. This method can be used to change the screenshots to the application's default image. This is applicable to apps with default passcode protection feature.
Xamarin.iOS
Adapted from https://stackoverflow.com/a/20040270/7561
Instead of just showing a color I wanted to show my launch screen.
public override void DidEnterBackground(UIApplication application)
{
//to add the background image in place of 'active' image
var backgroundImage = new UIImageView();
backgroundImage.Tag = 1234;
backgroundImage.Image = UIImage.FromBundle("Background");
backgroundImage.Frame = this.window.Frame;
this.window.AddSubview(backgroundImage);
this.window.BringSubviewToFront(backgroundImage);
}
public override void WillEnterForeground(UIApplication application)
{
//remove 'background' image
var backgroundView = this.window.ViewWithTag(1234);
if(null != backgroundView)
backgroundView.RemoveFromSuperview();
}

[CustomViewController respondsToSelector:]: message sent to deallocated instance

This is used to work fine for my pre-ARC code, but since refactoring all the project to be ARC compatible, I start getting this crash:
[CustomViewController respondsToSelector:]: message sent to deallocated instance
My project is an iPad app with a split view, but contrary to apple documentation, previous developer has put another view controller to be visible on app launch before split view. So I know this is not the right way to do, but as I said it used to work before ARC integration so I need to get a workaround with this.
The root view controller which contain a menu of items, each item display a detail form to be filled, then a click on next button move to the next detail screen, etc.
The issue starts when I click on home button put on root view to get back to the home view, here is the relevant code that move the user to the home screen:
//this method is in the appdelegate, and it gets called when clikc on home button located on the root view
- (void) showHome
{
homeController.delegate = self;
self.window.rootViewController = homeController;
[self.window makeKeyAndVisible];
}
Then when I click on a button to get back to the split view (where are the root/details view), the app crashes with the above description. I profiled the app with instruments and the line of code responsible of that is located in the RootViewController, in the didSelectRowAtIndexPath method, here is the relevant code:
if(indexPath.row == MenuCustomViewController){
self.customVC=[[CustomViewController alloc] initWithNibName:#"CustomVC"
bundle:nil];
[viewControllerArray addObject:self.customVC];
self.appDelegate.splitViewController.delegate = self.customVC;
}
customVC is a strong property, I tried to allocate directly and assign to the instance variable but that didn't help to fix the crash. Any thoughts ?
EDIT:
Here is the stack trace given by instruments:
[self.appDelegate.splitViewController setViewControllers:viewControllerArray];//this line caused the crash
[viewControllerArray addObject:self.appDescVC];//this statement is called before the above one
self.custinfoVC=[[CustInfoViewController alloc] initWithNibName:#"CustInfo" bundle:nil];//this statement is called before the above one
self.appDelegate.splitViewController.delegate = self.appDescVC;//this statement is called before the above one
custinfoVC and appDescVC are strong properties.
I solved this problem by setting my delegates and datasources to nil in the dealloc method. Not sure if it'll help you but its worth a try.
- (void)dealloc
{
homeController.delegate = nil;
//if you have any table views these would also need to be set to nil
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
}
You may want to setup the CustomViewController during app launch, and display the other views modally on top if necessary. The error message you're getting is because something is getting released by ARC prematurely. It might have not manifested before because pre-arc stuff wasn't always deallocated immediately. ARC is pretty serious about releasing stuff when it leaves scope
Hard to tell without seeing a lot more of the code involved, and what line it breaks on, etc.
This:
- (void) showHome {
//THIS: where is homeController allocated?
homeController.delegate = self;
self.window.rootViewController = homeController;
[self.window makeKeyAndVisible];
}
EDIT:
Add this line right above the line that causes your crash
for (id object in viewControllerArray) {
NSLog(#"Object: %#",object);
}
I had the same Problem.If you are not using "dealloc" method then use "viewWillDisappear" to set nil.
It was difficult to find which delegate cause issue, because it does not indicate any line or code statement for my App So I have try some way to identify delegate, Maybe it becomes helpful to you.
1.Open xib file and from file's owner, Select "show the connections inspector" right hand side menu. Delegates are listed, set them to nil which are suspected.
(Same as my case)Property Object like Textfield can create issue, So set its delegate to nil.
-(void) viewWillDisappear:(BOOL) animated{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController]){
self.countryTextField.delegate = nil;
self.stateTextField.delegate = nil;
}
}

blank QLPreviewController in iOS application

I am trying to display a file using QLPreviewController. The QL view displays correctly (is pushed on top of my Navigation Controller) but the content is blank. However, no errors are displayed and application doesn't crash.
Checks on existence of file return true. (A proof is that if I use [self.docInteractionController presentPreviewAnimated:YES]; where docInteractionController is a UIDocumentInteractionController the file is correctly shown).
The code is taken directly from Apple sample code DocInteraction.
previewController.dataSource = self;
previewController.delegate = self;
// start previewing the document at the current section index
previewController.currentPreviewItemIndex = 0; //I want the first (and only) document
[[self navigationController] pushViewController:previewController animated:YES];
[previewController release];
The current view is a QLPreviewControllerDataSource, QLPreviewControllerDelegate,, and the delegate methods are as follow:
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return self.documentURLs.count;
}
- (id)previewController:(QLPreviewController *)previewController previewItemAtIndex: (NSInteger)index
{
return [self.documentURLs objectAtIndex:index];
}
documentURLs is a NSArray that contains the fileURLs of the documents. The same fileURL passed to the UIDocumentInteractionController displays correctly. I don't necessarily have to use QuickLook, I may just rely on UIDocumentInteractionController, however the fact that it's not working is really annoying.
Thank you in advance
Giovanni
Make a sample that demoes the issue. If you find that it still occurs on iOS 7, pls file a bug report.
I reported a bug on this class (pass nil URL to get loading indicator) and it got fixed within 2 weeks.

Resources