Delegate methods no longer called after converting to use Automatic Reference Counting - objective-c

I've converted an app I'm writing to ios 5 and then using the inbuilt tool I converted it to use Automatic Reference Counting. There were no problems with ios 5 but after ARC conversion most of my delegate calls don't seem to be working. For example I have a subclass of UITableViewController with a .h file that looks like:
#interface UITableVCSubclass : UITableViewController <UITableViewDelegate, ... >
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
...
#end
The Table View Delegate method tableView:didSelectRowAtIndexPath: no longer gets called when I select a row of the table. If checked that self.tableview.delegate == self, which it does. Any ideas why this has stopped working?

I had the same issue and couldn't find a good reference so hopefully this will help someone else. My working project didn't work after running the ARC refactoring doohickey. The view controller for my UITableView was being created on the fly and pushed without saving a reference, which is not something the conversion process looks for.
ARC was releasing the vc when it fell out of scope, so the view was visible but its delegate was gone. To fix it I added a strong property to the super to hold a reference to the new view controller and then I started receiving events again.
Changed from this:
MyViewController *myViewController =
[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
To using the new property:
self.myViewController =
[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];

Related

Confusion with UINavigationControllers in SplitViewController

I am setting up an iPad app that uses a SplitViewController. In my app delegate I have the following in didFinishLaunchingWithOptions:
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *leftNavController = [splitViewController.viewControllers objectAtIndex:0];
LeftViewController *leftViewController = (LeftViewController*)[leftNavController topViewController];
DetailViewController *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
NSLog(#"Detail View Ctrl >> %#", [detailViewController class]);
When I run the app, the NSLog statement returns "UINavigationController" when DetailViewController is actually a subclass of UIViewController. However, in XCode, code completion shows all the methods that are implemented in the DetailViewController subclass. Any ideas? Thanks!
I think your DetailViewController is actually embedded inside a UINavigationController, and your fourth line is in error. Take a look instead at the topViewController for the second view controller inside your split view controller, much like you do for the LeftViewController.
The reason Xcode is continuing to suggest completion for DetailViewController methods is because you've given it that type. Code completion doesn't rely on runtime behavior (how could it?) – instead, it relies on static analysis of the code that you type. If you tell Xcode that something is a DetailViewController, it'll believe you and autocomplete based on that information.

Xcode: Document-based app window is not loading during attempt to subclass NSWindowController

I really haven't done much and i'm already stuck.
So far i've done:
added NSWindowController subclass (MikesWindowController.h & .m)
removed windowNibName from MikesDocument.m (since i'm implementing my own
WindowController subclass.)
I tried:
Tested if NSLog would come back at init, windowControllerDidLoadNib, applicationDidFinishLaunching. Only the NSLog at init printed.
And, tested the Main Menu -> File -> New after after compiling my Document app.
Am I implementing this right? Thanks. Any suggestions would be great! Under MikesDocument.m
-(void)makeWindowControllers{
MikesController *controller = [[MikesWindowController alloc]init];
[self addWindowController:controller];
}
After much deliberation I found that answer. Woohoo. Enjoy future.
removed initWithWindow from my NSWindowController subclass
implemented initWithWindowNibName to my NSWindowController subclass so now anytime I initialize I must specify the window nibName.
Below I implemented initWithWindowNibName in my NSWindowController subclass heres what it looks like:
MikesWindowController.m
-(id) initWithWindowNibName:(NSString *)windowNibName{
self = [super initWithWindowNibName:windowNibName];
return self;
}
(Below) Back again to the main document I corrected the makeWindowController method and instantiated my controller with "MikesDocument" (for MikesDocument.xib) and added it.
MikesDocument.m
-(void)makeWindowControllers{
MikesWindowController *controller =
// must tell controller which nib file to use.
[[MikesWindowController alloc]initWithWindowNibName:#"MikesDocument"];
[self addWindowController:controller];
}
Success! Don't even bother calling init or implementing init as it returns an error at any time.

Push to UIViewController dynamically

I am a newbie in iPhone application development.
I am developing an iPad application. It contains a menu bar on top, clicking on which retrieves a sub view. The sub view consists of UIPickerView. Upon selecting a row from UIPickerView, navigates to another UIViewController.
The UIPickerView methods are written in a separate class (As this functionality comes throughout the app, I made it a general one). So,
[self.navigationController pushViewController:controller animated:YES];
will not work for me!
I was able to get the name of the class to be pushed (It changes according to the selection made). Is there any way I can do it?
Thanks In Advance :-)
I guess what you really want is to create an object from a classname
The simple answer is
[[NSClassFromString(className) alloc] init...]
For a more thorough answer you should look at Create object from NSString of class name in Objective-C
You can use delegate method (delegate methods allows communication between objects) to implement this scenario
For example in your UIPicker(.h) class define a delegate protocol as follows
#protocol pickerProtocol;
#interface MyPicker : NSObject {
id <pickerProtocol> pickerDelegate;
}
#property(nonatomic,retain) id <pickerProtocol> pickerDelegate;
#end
#protocol pickerProtocol
- (void) pushViewController;
#end
And call this delegate method when selecting a row from UIPickerView
[pickerDelegate pushViewController];
Then in all view controller that uses picker write the implementation of the delegate method
- (void) pushViewController {
[self.navigationController pushViewController:controller animated:YES];
}
dont for get to set the delegate as follows
MyPicker *picker = [MyPicker alloc]init];
picker.pickerDelegate = self;

Custom back button UINavigationController across my entire app

I am looking to replace the back button in the UINavigationController throughout my application. My requirements is that this back button be defined in one XIB and if possible, the code to set it is in one place.
I have seen various methods that set the property self.navigationItem.backBarButtonItem to be a UIBarButtomItem with the custom button as it's view, e.g. [[UIBarButtonItem alloc] initWithCustomView:myButton];
My first thought was to create a global category (not sure if that's the term, I'm new to Objective-C as you might have guessed) that implements 'ViewDidLoad' for all my UINavigationControllers, and setting this property. My problem is loading the XIB to this button that I create at runtime.
Does anyone have a suggestion on a neat way of doing this (I guess it must be a common thing to do, and I can't imagine repeating code in all my screens). I have considered creating a UINavigationController subclass, however I wasn't sure how this would effect my custom implementations of ViewDidLoad.
Any advice much appreciated. Also I need to target >= iOS4 (the appearance API is iOS5 only).
I prefer to not force inheritance where possible so you could do this with two categories
#interface UIViewController (backButtonAdditions)
- (void)ps_addBackbutton;
#end
#implementation UIViewController (backButtonAdditions)
- (void)ps_addBackbutton;
{
// add back button
}
#end
#interface UINavigationController (backButtonAdditions)
- (void)ps_pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
#end
#implementation UINavigationController (backButtonAdditions)
- (void)ps_pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
{
[viewController ps_addBackbutton];
[self pushViewController:viewController animated:animated];
}
#end
Now #import these files as appropriate and instead of using
[self.navigationController pushViewController:aViewController YES];
use
[self.navigationController ps_pushViewController:aViewController YES];
Disclaimer
I free styled this in the browser so you may need to tweak it
I had the same issue in my current project, the solution I came up with was to create a MYBaseViewController base class without xib and there in viewDidLoad programmatically (if you want to init barButtonItem with custom view, you are not able to create in xib anyways) create a customBackButton (and of course release it and set to nil viewDidUnload.
This works good for me because this way I can create xibs for all my other viewControllers that are subclasses of MYBaseViewController(if you created a view for base class in nib you would not be able to create a nib for a subclass).

Values not passed back after dismissModalViewController

I'm passing a string variable for the sake of testing (isLoggedIn) as well as an NSManagedObject (userObject). However, when I dismiss the VC and it comes back to the root, I do not have the new data that was set in the variables in the loginViewController.
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
loginVC.managedObjectContext = self.managedObjectContext;
loginVC.userObject = self.userObject;
loginVC.isLoggedIn = self.isLoggedIn;
[self presentModalViewController:loginVC animated:YES];
[loginVC release];
I later dismiss the view with:
[self dismissModalViewControllerAnimated:YES];
Update:
Ended up using delegates as someone suggested. I used the following post as a guideline:
UIViewController parentViewController access properties
I ended up using delegates as someone above suggested. I used the following post as a guideline:
UIViewController parentViewController access properties
I may not be following you properly so this could be irrelevant.
I am guessing you mean that:
You set your ivars after alloc/init
You make some changes inside LoginViewController
You expect those changes to be reflected in self.userObject and self.isLoggedIn of the class that instantiated LoginViewController
which may or may not happen if you act on the objects themselves or you reassign the pointers
e.g.
If you call self.userObject.name = #"Test"; inside LoginViewController then the change will be reflected in the class that instantiated LoginViewController and LoginViewController because the ivars are pointing to the same object in memory and you are manipulating the object.
OR
If you call self.userObject = theResultOfSomeNewFetch; then the change will not be reflected as you now have a pointer in LoginViewController that is pointing to a different userObject to the pointer in the class that called LoginViewController
Hopefully I have not lost the plot completely and this is somewhere near what you mean.