ios warning calling init method of a uiviewcontroller - objective-c

I have my custom viewcontroller declared like this:
#interface DetailViewControllerSpeciality2 : UIViewController <UITableViewDelegate, UITableViewDataSource> {
}
and I create a new instance like this:
DetailViewControllerSpeciality2 *detailViewControllerSpeciality = [[DetailViewControllerSpeciality2 alloc] init];
but xcode tell me a warning:
multiple methods named '-init' found
but I don't have declared a -init method...

You aren't showing all the error message, nor the relevant code. Still, there is enough evidence to make an educated guess.
More likely than not, you have an init method declared like:
- (DetailViewControllerSpeciality2 *) init;
The compiler is complaining because that conflicts with NSObject's init (that returns id).
Declare your init to return id and the compiler should be happy. If that isn't the problem, post more code.

try this.
[[DetailViewControllerSpeciality2 alloc] initWithNibName:nil bundle:nil];

Related

Setting Delegate and Lazy instantiation

I have an App with an NSWindowController and an associated XIB which is not needed most of the time (admin interface window), so I wanted to use Lazy instantiation. However, I also need to setup the 'delegate' and that is when the errors happen.
I have everything setup in the AdminWindow,h (subclass of `NSWindowController') and .m file.
In my main controller, MainController (subclass of NSObject) I have the following working code.
#interface MainController : NSObject<AdminWindowDelegate>{
AdminWindow *myAdminWindow;
}
#implementation MainController
-(id)init{
myAdminWindow = [[AdminWindow alloc] init];
[myAdminWindow setDelegate:self];
}
-(IBAction)openAdminWindow:(id)sender{
[myAdminWindow showWindow:nil];
}
So that all works, but I don't want to instantiate myAdminWindow until it's needed, thought lazy instantiation would work.
Altered the MainController:
#implementation{
-(AdminWindow *) myAdminWindow{
if(!_myAdminWindow){
_myAdminWindow = [[AdminWindow alloc] init];
//Tried to set delegate here, but does not work
}
-(IBAction)openAdminWindow:(id)sender{
[self.myAdminWindow showWindow:nil];
}
Where do I set the delegate? I tried just after 'alloc' 'init' of myAdminWindow, but it does not work. when I start typing the command
_myAdminWindow.setDe... Xcode gives nothing, .setDelegate or .delegate are not options.
I've tried
[_myAdminWindow setDelegate Nope, does not work either.
Leaving out the delegate portion, everything else works as desired.
Question: When using lazy instantiation , where do I set the delegate? and how?
Thank you in advance
===[EDIT]===
In case someone else has the same question.
Thank you to Phillip Mills for the reply and reminder.
I removed the following declaration in #interface of MainController:
AdminWindow *myAdminWindow;
And declared myAdminWindow in the MainController's interface section as a property - and all is good!

Objective-C: why a custom object will be a zombie

I'm developing an app in Objective-C using ARC.
My simplified code looks like this:
ClassA (.m)
MyCustomClass *obj = [[MyCustomClass alloc] initWithValue1:#"abc" value2:1000];
MyViewController *vc = [[MyViewController alloc] initWithObject:obj];
// "vc" will become the first item of a UITabBarController
MyViewController (.h)
- (id)initWithObject:(MyCustomClass *)obj {
...
localReferenceToOjbect = obj;
...
}
- (void)viewWillAppear:(BOOL)animated {
// do something with "localRefernceToObject" <---
}
launching the app will result in a call to a zombie: when the ViewController is shown, the "obj" will be already deallocated and so i can't use it anymore.
my workaround is:
ClassA (.h)
#interface ClassA : UIViewController {
MyCustomClass *obj;
}
ClassA (.m)
obj = [[MyCustomClass alloc] initWithValue1:#"abc" value2:1000];
MyViewController *vc = [[MyViewController alloc] initWithObject:obj];
// "vc" will become the first item of a UITabBarController
is this the right way?! i don't think so: why i've to store an istance of an object that is useless for ClassA?
i can't get an explanation on what's actually happening. could you help me?
You're right in the fact that it is not logical to keep around a reference to obj in ClassA.
But if you need to keep around the reference to obj for MyViewController to use it, retain it in MyViewController, not in ClassA, because that's MyViewController that will use it.
The easiest way to do this is to transform your localReferenceToObject you use in MyViewController into a #property(retain) propertyToObject; (or #property(strong) propertyToObject if you use ARC) and access it in your MyViewController.m with self.propertyToObject (instead of localReferenceToObject, to be sure to call the property's setter and thus really retain the object).
This way, the object will be retained and kept around while your MyViewController instance is still alive.
[EDIT] If you want this property to be private, you can declare it in the class extension so that it is not accessible from other classes, as in the below example. See here in Apple's documentation for more details.
In your MyViewController.h header file
#interface MyViewController : UIViewController
// Here you write the public API in the .h / public header
// If you don't want your property to be visible, don't declare it there
#end
In your MyViewController.m file
#interface MyViewController ()
// This is the private API, only visible inside the MyViewController.m file and not from other classes
// Note the "()" to declare the class extension, as explained in Apple doc
#property(nonatomic, retain) MyCustomClass* referenceToObject; // Note: use strong (which is a synonym of retain) if you use ARC
#end
#implementation MyViewController
#synthesize referenceToObject = _referenceToObject; // not even needed with modern ObjC and latest LLVM compiler
- (id)initWithObject:(MyCustomClass *)obj
{
self = [super init];
if (self) {
...
self.referenceToOjbect = obj;
...
}
return self;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// do something with "self.refernceToObject"
}
// This memory management code is only needed if you don't use ARC
-(void)dealloc
{
self.referenceToObject = nil; // release memory
[super dealloc];
}
Personally, as suggested by Apple in some WWDC sessions, I now really rarely use instance variables and prefer the use of properties instead, either public in the .h or private in the .m.
If you use ARC, you can still use an instance variable instead of a property as ARC will retain it for you, but as long as you make sure your instance variable is declared as strong and not weak.

Selector Sent to method overridden in Category fails

I am trying to override a UIStoryboard method using a category. Here is my implementation:
#import "UIStoryboard+SomeCategory.h"
#import <UIKit/UIKit.h>
#implementation UIStoryboard(SomeCategory)
-(id)instantiateInitialViewController
{
NSLog(#"SUPER CLASS: %#", [super class]); // logs "UIStoryboard"
NSLog(#"SUPER RTS : %#", [super respondsToSelector:#selector(instantiateInitialViewController)] ? #"YES" : #"NO"); // logs "YES"
return [super instantiateInitialViewController];
}
#end
when I add:
UIViewController *viewController = [super instantiateInitialViewController]
Why do I get the compiler error:
Receiver type 'NSObject' for instance message does not declare a method with selector 'instantiateViewController'
If you use super when overriding methods using a category, the method will be called on the superclass of the object, not the object you are overriding the method on. You haven't made a subclass of UIStoryboard, so super refers to NSObject - which is reflected accurately in your error message.
I don't know what's going on with your log messages, though.
Using a category to override a method means that you can't call the original method. You'll need to either make a subclass of UIStoryboard or an entirely new method in the category, that calls [self instantiateInitialViewController].
You should note that [super class] is not the same as [self superclass]. Quoting the docs:
Objective-C provides two terms that can be used within a method definition to refer to the object that performs the method—self and super.
They differ in how the compiler will search for the method implementation, and in some cases they will mean just the same.
In this case you want:
NSLog(#"SUPER CLASS: %#", [self superclass]); // logs "NSObject"
to check an object's super class class, and you'll need a UIStoryBoard subclass, not a category, to be able to use:
return [super instantiateInitialViewController];
Why [super class] doesn't log what you expect is another subject. If you're interested, this post What is a meta-class in Objective-C? is a good starting point.
You need to use method swizzling. good explanation of how to use it for your purposes here: http://b2cloud.com.au/how-to-guides/method-swizzling-to-override-in-a-category
If you really want to call that method from a UIViewController, your category should be:
#implementation UIViewController(SomeCategory)
Even so, it would call the super of your UIViewController, so it would still not work. You also need to do the following:
UIViewController *viewController = [self instantiateInitialViewController]

setDelegate:self generates a caution flag

I am trying to learn Objective C and have an error in the code for one of my lessions and I do not know how to solve it.
Code:
// AppController.m
#import "AppController.h"
#implementation AppController
- (id)init
{
[super init];
speechSynth = [[NSSpeechSynthesizer alloc] initWithVoice:nil];
[speechSynth setDelegate:self];
voiceList = [[NSSpeechSynthesizer availableVoices] retain];
Return self;
}
From [speechSynth setDelegate:self]; I get the error: Sending 'AppController *' to parameter of incompatible type 'id< NSSpeechSynthesizerDelagate>'.
The program compiles with a caution flag and seems to run correctly. I have compared my code with the author's code and can find no differences and none of my searches have indicated I should get an error on this line. The book was written for Xcode 3 and I am using Xcode 4.0.2.
Any suggestions or pointing me in the right direction would be greatly appreciated. Thanks.
Xcode is warning you that the setDelegate method expects an instance of a class that has implemented the NSSpeechSynthesizerDelagate protocol. Now, you have, but you've probably just forgotten to declare that you have. In your class declaration, change
#class AppController : NSObject
to
#class AppController : NSObject<NSSpeechSynthesizerDelegate>
to tell the world "I obey NSSpeechSynthesizerDelegate!", and silence the warning. You never know - you might get warned that you've forgotten to implement some non-optional delegate methods, and save yourself an annoying bug somewhere down the line.
When you cast the self object then warning message disappears.
[speechSynth setDelegate:(id < NSSpeechSynthesizerDelegate >) self];

Why is my method not found?

I have a custom init method for my SecondViewController : UIViewController
-(id) initWithFirstViewController:(FirstViewController *)theFirstViewController
{
self = [super init];
fvc = theFirstViewController;
return self;
}
So in my FirstViewController I call this init method with an instance of the FirstViewController as a parameter. Somewhere else in the SecondViewController I use this passed intance:
[fvc setSomething];
The method is executed but I get a warning:
Method -setSomething not found (return type defaults to id)
How to fix this?
In this case, it's a matter of #importing the corresponding .h file so the compiler knows about the method.
Additionally, you should retain theFirstViewController as chances are that it gets released and a different object is created at exactly the same memory location (to which fvc is still pointing). So you should do fvc = [theFirstViewController retain]; as you are "holding on to" the first view controller (you want to make use of it later on). Don't forget to release it in your dealloc.