App suddenly crashes while processing presentViewController method in iOS 7.1 - ios

Today, I upgrade my Xcode to the latest version(Version 5.1 (5B130a)) to support iOS 7.1.
After doing this, I run my project in Xcode as usually. Then app crashes.
I didn't change any code before upgrading the SDK version.
The code is running perfectly in iOS 5.x, 6.x, 7.0.x.
I am simply presenting another view controller in the current view controller.
they are both initialized by storyboard.
While processing presentViewController method, it gets a error message "Thread 1: EXC_BAD_ACCESS (code=2, address=0x60)". I have checked the variables, they are both alive, not a released garbage.
What's the problem with iOS 7.1??
the project is using non-ARC mechanism.
Here is my code:
#property (nonatomic, retain) ArticleViewController *articleView;
....
self.articleView = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"ArticleViewController"];
...
[self presentViewController:self.articleView animated:NO completion:^() {
log(#"has shown article page...");
}];
but it works fine if presenting another view by using addSubView function:
[self.view addSubView:self.articleView.view];
I really don't know why this happens.

This happened to my app while presenting a view controller with modalPresentationStyle = UIModalPresentationCustom;
Here's how my code looks like on iOS 7.0:
//Inside my MyPresentedViewController:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[self setupContent];
}
return self;
}
- (void)setupContent
{
//TransitionManager adopts UIViewControllerTransitioningDelegate and UIViewControllerAnimatedTransitioning
TransitionManager *transitionManager = [[TransitionManager alloc] init];
transitionManager.presenting = YES;
self.modalPresentationStyle = UIModalPresentationCustom;
self.transitioningDelegate = transitionManager;
}
However, the above code crashes on iOS 7.1 so I changed the implementation to:
#interface MyPresentedViewController
#property (nonatomic, strong) TransitionManager *transitionManager;
#end
...
//Inside my MyPresentedViewController:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[self setupContent];
}
return self;
}
- (void)setupContent
{
//TransitionManager adopts UIViewControllerTransitioningDelegate and UIViewControllerAnimatedTransitioning
self.transitionManager = [[TransitionManager alloc] init];
_transitionManager.presenting = YES;
self.modalPresentationStyle = UIModalPresentationCustom;
self.transitioningDelegate = _transitionManager;
}
Basically, instead of declaring a transitionManager object inside the setupContent method, I created a private property (strong reference) for it.

Hm the only thing I can think of is ensuring that your articleView property is a strong reference.
#property (nonatomic, strong) ArticleViewController *articleView;

I ran into a similar issue with a picker view. In my case the pickerview was set to nil after the selection handler block, although this caused no issues as recently as last night, it was causing the app to crash this morning. Removing that line fixed the issue, however I have converted this project to ARC in the last month so you may have to find a better way to handle clean up.

This may be completely unrelated to the stated problem or answers but I ran into a similar problem when accessing an NSString on an iPhone 5S. The exact same code runs fine on an iPad and iPad at the same time.
To start out with I think it's important to state that I'm running under ARC, and I have been told repeated not to "release" any objects I instantiate in my functions. I've had problems with this before so I use some of my C# background to set almost all of my local variables to nil (null in C#). Yes, I don't trust MS GC either.
Back to the problem at hand; I have an NSString called 'data'. 'data' is read as a result from another method in a different class. Using NSLog I can see the contents of 'data'. On the next line I convert 'data' to an array to use it in scanf. That still works. On the third line I try to NSLog 'data' again, but then I get the EXC_BAD_ACCESS error. Each time it has a different address. I'm even less comfortable with ARC than I am with the Microsoft Garbage Collector so I wrapped the function in a try..catch..finally. 'data' is now sitting outside of the try..catch..finally. I'm setting 'data' to nil in the finally, which seems to fix the problem.
I know this was a bit long winded, but I would really appreciate it someone could explain why this would happen. I'm expecting to see a lot of these problems to popup all over my code now.

Related

Using blocks to pass data back to view controller

I was looking at this question.
One of the answers shows how to use blocks to pass data backwards view the prepareForSegue method. My understanding is this method should really be used to pass data forward, not backwards.
I'm wanting to try blocks out for this purpose - passing data back to another viewController.
My question is: How do I do this, without using prepareForSegue method?
I could use for instance in a UITableView - didselectRowAtIndexPath and dismiss the view - but then how does the receiving view get "notified" there is data to come back, without using a delegate?
sent data backward
declare block in your secondViewController.h file
#property (nonatomic, copy)void(^myBlock)(NSString *);
call block wherever you need to pass data from .m file of secondViewController
myBlock(#"this will displayed in firstViewController");
3.import above .h file in your firstViewController .m file
and define your block as
secondViewController *ref =[[secondViewController alloc ]init];
ref.myBlock =^void(NSString *data)
{
self.labelOffirstviewcontroller=data;
};
In your view controller 1:
MyViewControllerClass2* vc2 = [[MyViewControllerClass2 alloc] initWithNibName:#"UIViewController" bundle:[NSBundle mainBundle] completion:^{
NSLog(#"view2 is closed");
}]];
[self.navigationController pushViewController:vc2 animated:YES];
In MyViewControllerClass2.m:
#interface MarryViewController ()
#property (nonatomic, copy) void(^completion)();
#end
#implementation MarryViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completion:(void(^)())completion
{
self = [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if( self )
{
//store completion block
_completion = completion;
}
return self;
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
//call completion block
_completion();
}
In MyViewControllerClass2.h:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completion:(void(^)())completion;
Just a few notes on how awesome block are:
MyViewControllerClass2 has no idea what is defined in _completion() which is the main point, as this is not of his concern
You could also call _completion() in -dealloc or even on some place where MyViewControllerClass2 will continue to run
You can pass arguments to block functions
You can pass arguments from block functions
Many more :)
I'm really encouraging people to get good overview on blocks and stat using them as they are pretty cool.
IMPORTANT!
While using block you do not declare delegate, the main idea and abstract result of delegate method and using block are the same. Moreover delegate pattern has it's advantages such as better documenting and more strictly usage. Still blocks are way more flexible and(when get used to) easier to use.
Regards,
hris.to
I know that you asked specifically for a solution that did not involve prepareForSegue but this appears to be based on the assumption that prepareForSegue is for passing data forward only.
There is something called an unwind segue which might be helpful in your situation. There is a detailed discussion on SO here.
If you specifically want to use blocks for this, you can simply add a block property to your child controller and have the parent controller set the block. The child controller would have to invoke the block when it is being dismissed. Beware of retain loops if you do this. It doesn't sound to me like blocks are the best solution in this context but it's difficult to say something like that with authority without having a lot more context.
Yes methods can send data forward as well as backwards for that you can use Blocks or Delegates
For more info about blocks in ios use this link
CLICK HERE
Hope it will help you, thnx

Initializing a View controller using initWithNibName

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
fetched = NO;
self.title = #"Nearby";
// Custom initialization
liked = NO;
categories = [[NSArray alloc] init];
fundings = [[NSArray alloc] init];
stages = [[NSArray alloc] init];
}
return self;
}
I use the code above. am I during anything wrong by initializing all of my varialbes in the initWithNibName function? Is that the correct place to do so?
You will probably not run into issues, but you can use a ViewController also with the pure init in which case the NIB is not loaded and also your initialization will not be called. Another place to make the init for that is the viewDidLoad which is called only after the init.
You can do it in the init method, that's fine. You could also do it (or some of) in the viewDidLoad method. The difference would (generally) be that viewDidLoad is called when your view is actually getting ready to be shown, so you need everything setup. init on the other hand could be called well in advance. There isn't a hard and fast answer, it depends what the items you're setting up are and if they can be unloaded when the view isn't on display. With newer versions of iOS that concern changes anyway as the view generally isn't unloaded. You really need to read about the view and controller life cycles and decide when to create and destroy your attributes.

In iOS prevent RootViewController to become God like by extra 'controller' to display MFMailComposeViewController

I've asked a question about the same issue before, and the solutions worked, but it was not a compatible iOS 4.3 solution, and I thought my design is not the right one.
Now I want to show a MFMailComposeView(Controller) as a modal view on top of my RootView(Controller) when i press a button. And instead of making it the delegate i want to make a simple NSObject which implements the protocol.
Who is also capable to show the MFMailComposeView(Controller) in the RootViewController.
I am trying this design/solution which gives me memory allocation/access problems.
RootViewController.m:
- (IBAction)tapExportButton:(id)sender
{
SendMailController *sendMailController = [[SendMailController alloc]initWithParentViewController:self];
[sendMailController openMailDialog];
[sendMailController release];
}
SendMailController.h
#interface SendMailController : NSObject <MFMailComposeViewControllerDelegate>
- (id)initWithParentViewController:(UIViewController *)parentViewController;
- (void)openMailDialog;
#property (retain, nonatomic) UIViewController* parentViewController;
#end
SendMailController.m
#import "SendMailViewController.h"
#implementation SendMailController
#synthesize parentViewController = _parentViewController;
- (id)initWithParentViewController:(UIViewController *)parentViewController
{
if (self=[super init]) {
self.parentViewController = parentViewController;
}
return self;
}
- (void) dealloc
{
self.parentViewController = nil;
[super dealloc];
}
- (void)openMailDialog
{
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
...
mailer.modalPresentationStyle = UIModalPresentationPageSheet;
[self.parentViewController presentModalViewController:mailer animated:YES];
[mailer release];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
...
// Remove the mail view
[controller.parentViewController dismissModalViewControllerAnimated:YES];
}
#end
When I set a breakpoint in the delegation method, it crashes already before that.
Is is something with the delegate property of mailer (MFMailComposeViewController)?
The problem is that you create your instance of SendMailController and try to show the composer view, and then you release the SendMailController. This causes it to be deallocated. It looks like it works because the composer view is on screen - this is because it has been retained by the presentModalViewController call.
To fix, you need to retain your instance of SendMailController and release it when the composer has been dismissed.
The correct way to do it (and required if you use ARC, and you should use ARC) is to provide a delegate callback to tell the owner that it's finished - which kind of makes the class pointless if all it does is wrap the composer.
The cheating way (which only works when not using ARC, and which you need to be very careful with) is to have your object retain itself when it presents the composer and release itself when the composer is dismissed.
The underlying problem being your root view controller containing all the logic, you should look at using child view controllers (if a single screen holds all your UI). Usually though, your root view should be the simple class (like a master list of options) and the views it presents would be more complex (the detail views). You need to look at ensuring that the appropriate class owns the responsibility for each screen of UI.

Leak detection issue in iOS with xCode 4.3

I have a very strange issue with the xCode 4.3 memory leak instruments... Basically it does not work in the following case...
Project is created without ARC support.
Create a simple class which inherits UIView
use a "button" to create instance of this class and "leak" it... the leak will not be catch by Leak Instruments
so here is the code of the PROBLEMATIC class
#interface LeakTestView : UIView
- (id)initWithFrame:(CGRect)frame;
#end
#implementation LeakTestView
- (id)initWithFrame:(CGRect)frame
{
NSLog(#"initWithFrame called");
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
#end
And now I create the leak...
- (IBAction)leak:(id)sender {
LeakTestView* leak=[[LeakTestView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
NSLog(#"class is %#", [leak class]);
}
So the problem is that this leak will not be detected...
If I change the base class to NSObject and instead of initWithFrame override init (see bellow) then the leak will be detected....
so here is the code for leak that WILL be detected
#interface LeakTestView : NSObject
- (id) init;
#end
#implementation LeakTestView
- (id) init {
NSLog(#"init called");
self = [super init];
if (self) {
}
return self;
}
#end
If I create object now and leave it - the leak detection will trigger and the leak will be "seen" into the Instruments.
- (IBAction)leak:(id)sender {
LeakTestView* leak=[[LeakTestView alloc]init];
NSLog(#"class is %#", [leak class]);
}
Any ideas what is going on? Why the leak of the UIView subclass will not be detected but changing the base class to NSObject will "fix" the issue?
Oh and yes the leaked object can be seen using the "Mark heap" - one mark before the leak and one mark after I click the button and create the leak - the class will be seen into the heap delta...
EDIT: one more "funny" situation... If I remove the "init" stuff (only alloc the object)
LeakTestView* leak=[LeakTestView alloc];
then the leak will be detected no matter what is the base class... What the hell is going on here?
EDIT2: one more "funny" thing. The Leak detection issue can be observed only in Simulator (iOS 5.0, 9A334 is mine) but the leak will be detected always if using the iPad device...
Any comments? If you dont have the issue or consider that I speek "lies" just tell me I am wrong and the above case is working "just fine" - leaks I describe are detected by your xCode instruments!
Maybe it is not leaking?
You are calling a method that is a black box. How UIView initWithFrame is implemented is none of your business. It has a contract of sorts, but you have no right to demand this to leak anymore than you can assume the retain count is 1.
Leaks is a useful tool but it doesn't do what you think it does. It does not tell you when you have messed up. It tells you when you have unreachable allocations. This is not the same thing.
Or, it might be a bug.

Subclassing IASKAppSettingsViewController

I'm trying to tweak the behavior of the default IASKAppSettingsViewController so it can provide custom subviewcontrollers (as for type = PSChildPaneSpecifier) for custom views (type = IASKCustomViewSpecifier).
I've tried to subclass IASKAppSettingsViewController without adding any new functionality to the code.
However when I load up my own subclass the settings view is completely empty - even for a bare subclass. When I switch back to the default IASKAppSettingsViewController everything works again as expected.
I've tried setting breakpoints various places in my subclass and everything seems to be working fine - except that nothing is displayed.
I've tried looking for clues in the documentation, but can't seem to find anything that explains why. The documentation for InAppSettingsKit even states that it's designed for subclassing.
What am I missing here? Any clues are appreciated - or even better a small step-by-step guide for dummies.
Updated with code:
Setting up the flipside view. It works with the standard IASKAppSettingsViewController but fails with my empty derived MyCustomSettingsViewController
- (IBAction)showInfo:(id)sender
{
// Setup navigation controller for settings view
MyCustomSettingsViewController *settings = [[MyCustomSettingsViewController alloc] init];
//IASKAppSettingsViewController *settings = [[IASKAppSettingsViewController alloc] init];
settings.delegate = self;
settings.showDoneButton = YES;
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:settings];
navigation.navigationBar.barStyle = UIBarStyleBlack;
[settings release];
// Display the settings
navigation.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigation animated:YES];
[navigation release];
}
Try to add this method to your subclass:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
return [super initWithNibName:#"IASKAppSettingsView" bundle:nibBundleOrNil];
}
If you don't do that, the default implementation of IASKAppSettingsViewController kicks in and it tries to find a nib named after your class name, in this case "MyCustomSettingsViewController.nib". This probably doesn't exist.
This happens because the default implementation of -init calls -initWithNibName:nil bundle:nil and nil as the filename means to search for a default nib.
Try setting breakpoint on initialization steps and if you are adding that as a subview/ pushing on navigation controller. Use NSLogs for each method so you can find the issue. If nothing works send me the code (create a demo code using IASKAppSettingsViewController) to recerate the problem then I'll look into the issue.

Resources