First of all, as I understand it, init in Objective-C, functionally is similar to a constructor in Java, as it is used to initialize instance variables and prepare a class to do some work. Is this correct?
I understand that NSObject implements init and as such it does not need to be declared in any .h files.
But how about custom implementation of init for a given class, for example:
(id) initWithName:(NSString *) name
Should declaration like this be listed as part of .h, or it is not necessary? Is it done by convention or is there any other reasoning?
init is by no means similar to constructor in Java/C++. The constructor always executes when the object is created. But the execution of init is up to you. If you don't send init message after alloc then it will not execute.
// init does not execute here
MyObject *obj = [MyObject alloc];
And this will work without any problems if you derive from NSObject, as init of NSObject does nothing.
You do not need to add init in the header file, because it is inherited from NSObject but you need to add custom init methods (that are not inherited) to the header file. Note that init methods are just normal methods with a naming convention, but technically there is no difference from other methods.
If you do not specify your custom init methods in the header file, but send that message to an object, the compiler will generate a warning. There will be no compile error. So if you decide to ignore the warning then you can omit that from header too. But you will get a runtime crash if the method is not actually implemented. So it's better to add all methods that are not inherited in header file.
Yes you have to declare it if you want to be able to call this personalized initialisation method (initWithName). And the first think you have to do in that method is to call [super init];.
Related
Question is in title. Code example:
UIViewController <MyProtocol> *viewcontroller = ...;
[viewcontroller methodFromProtocol]; // I expect to be able to call all methods that the protocol defines
//UIViewControllerSubclass implements MyProtocol
UIViewControllerSubclass *viewControllerSubclassWithoutMyProtocol = [[UIViewControllerSubclass alloc] init];
[viewControllerSubclassWithoutMyProtocol methodThatIsNotInTheInterfaceIsDisplayedHere]; // I only expect to be able to call the methods that are defined in this class' interface even though this class implements MyProtocol
Your question isn't completely clear, but I think you are asking if you can "privately" conform to a protocol?
This can be done by declaring that you conform to the protocol inside the implementation file, rather than the interface file. With view controllers, you can do this in the class continuation that is generated for you automatically in the .m file, otherwise you'll need to add the class continuation in yourself:
#interface MyVCSubclass () <MyProtocol>
Now, any class that imports only the header file will not know your controller conforms to the protocol.
[viewControllerSubclassWithoutMyProtocol methodThatIsNotInTheInterfaceIsDisplayedHere];
I only expect to be able to call the methods that are defined in this class' interface even though this class implements MyProtocol
That's a bad expectation. Objective-C lets you call any method that an object implements. If you try to call a method that an object doesn't implement, two things should happen:
You get a compiler warning (not an error though)
When the code runs, it crashes, unless you've taken steps to handle such an event.
If a class implements a protocol but doesn't declare that it does so in a public header, then you can still call the method (since Objective C doesn't have private methods). I'd have thought you'd get a compiler warning, but if you're calling this from a file within the same Xcode project as your object (that is, you're not building a static library) then it's possible that Xcode is getting smart and deciding that since the method exists, it must be OK to call.
It wasn't clear from your question what you expected to happen and what actually happened. If you supply that information, we'll be able to give better answers.
Let's say I have this class and its subclass
#interface MySuperClass
- (void)open:(id)type value:(id)value;
- (void)openWebpage:(NSURL*)url;
#end
#interface MySubClass
- (void)openWebpage:(MyBookmarkClass*)bookmark;
#end
and that calling [someMySubclass openWebpage:someBookmark] calls [super open:BookmarkClass value:self.url]. And open:value calls [self openWebpage:url].
I realize this is very contrived, but I ran into a similar situation. My confusion is that even though [self openWebpage:url] is being called in MySuperClass, when it gets executed openWebpage: is being run in the context of the caller, MySubClass, which doesn't know what to do with an NSURL.
So my question is: is there any way to force something to be called in its original context? Or make it as though it calls super as many time as it can up the chain and find the method closest to the top?
There is only one context. There's a single object. Its class is MySubClass.
It is a mistake to have overridden the method with a different incompatible type. Don't do that. This is not C++ with function overloading. There's no dispatch based on the type of arguments.
The convention is to name methods by what they're acting on. So, you may have a method named -openWebpageURL: in MySuperClass and another method introduced in MySubClass named -openWebpageBookmark:. Note that MySubClass would still have a method named -openWebpageURL: inherited from MySuperClass.
If I generate methods dynamically on runtime and then call them - how can I convince compiler that the class will respond to undeclared (generated) methods and make it not throw warnings?
Update in regard to answers
When I generate the methods - their name is not known at compile time. To give an example - if I have a view controller MyFooController and it's initiated with method initWithFoo:(Foo*)foo, I'd be able to generate method like pushMyFooControllerWithFoo:(Foo *)foo for UINavigationController. Hence you notice that declaring such methods would be counter-productive.
This doesn't directly answer your question, but if I was generating method names (presumably from strings), I would call them using the string names, hence bypassing the compiler warnings.
[fooController performSelector:NSSelectorFromString(#"pushMyFooControllerWithFoo:") withObject:foo];
That way you are responsible for the validity of the generated method names.
Since you are adding methods on runtime, so you should also invoke them with runtime function, objc_msgSend or performSelector:withObject:for example, so the compiler will not going to warn you anything.
Well, if you call them, you know their signature, and if you know their signature, you can declare them, can't you?
Declare this method in a category for NSObject and make an empty implementation:
#interface NSObject (DynamicMethodsCategory)
- (void)doSomething;
#end
#implementation NSObject (DynamicMethodsCategory)
- (void)doSomething
{
}
#end
In your object you can call it without any warnings:
#implementation MyObject
- (void)someMethod
{
[self doSomething];
}
#end
Then generate implementation of [MyObject doSomething] dynamically, it will be called instead of NSObject's one.
Update:
Alternatively, the method can be declared in a category for the object. This suppresses the compiler's Incomplete implementation warning. However, I think this is not a good workaround, because the application will crash if the method is not created dynamically in runtime before it is called.
In my quest to be the grandmaster of Objective C, I keep running into it's subtleties, which I want to share with ya'll and gain an understanding why
1) I have two init methods, the one that is inherited by NSObject for my Objective C class and one is a custom method that I create off my own, let's say
initCustomMethod:(int)par1 argument2:(int)par2;
My Aim is to call initCustomMethod through the provided init method, essentially
-(id)init{
return [self initCustomMethod:1 argument2:3];
}
Naturally, maintaining the order, I have init appearing before initCustomMethod in the .m file. Xcode warns me telling me that the initCustomMethod is not found, I go ahead and shuffle the order and have init appearing after initCustomMethod is declared and there is no such warning message anymore and everything is fine.
I concur that the order is important since it's essentially derived from C, however I am not sure of this. Because, i shuffled the order of some properties and their custom methods, with the properties #synthesize being declared after the custom setter method for a given property, but there was no such error replica.
Can anyone point out the malice here?
Thanks guys!!!
Very cool guys, thanks for helping me out with this. Also, since I have a custom init method, I am initializing the super in this method and using the original init method to call the custom init method.
Anything wrong with this?
Before you reference it anywhere, you should declare initCustomMethod:argument2 in your interface, which would usually be in your header file.
For example, you would usually have a .h file that looks like:
#interface MyClass
{
//instance variables
int anInstanceVariable;
}
// properties
#property (nonatomic, assign) int aProperty;
// methods
-(id)initCustomMethod:(int)par1 argument2:(int)par2;
#end
And if you did this, the order in which you define init and initCustomMethod:argument2: won't matter. This is because the declaration tells the compiler that you are going to define the method, and what it will look like, so it isn't confused when you use it later.
It's a bad idea in Objective-C to use a function or a method before it is either declared or defined. Putting initCustomMethod:argument2: before init means that the former is already defined in the latter. But if you'd just declare it in the header, it wouldn't matter which order they went in.
Add your custom method name in your header file - the compiler just goes through things in order. If you don't have a forward declaration, the compiler won't know what to do with that call. You're going to need to put it in the header if you want other parts of your program to be able to call it anyway.
I have class named 'WebServicesiPhone' .... I want to create an instance of this class and do some json parsing functions and store the result contents into some arrays in the Delegate class ...
how can I declare an instance of this class in some other class ....which is the best way ....
WebServicesiPhone *newsParser = [[WebServicesiPhone alloc] init];
[newsParser getData:0:nil:0:0];
[newsParser release];
or i have to declare a instance in other class's .h file .. like this
WebServicesiPhone *newsParser;
and allocate in method file .. if i am using this method whrere i have to release the object after my use .....
newsParser = [[WebServicesiPhone alloc] init];
I think you're mixing some terms so I'll try to explain as simple as possible.
WebServicesiPhone *newsParser; is not an instance, it's a variable. If declared in .h file between curly braces, it's an instance variable, as every instance of your class will have one. If it's declared somewhere in .m file, it's a local variable and will only be available inside the block of code where you declared it.
[[WebServicesiPhone alloc] init]; instantiates a new object of type WebServicesiPhone, also called an instance, and when you assign value of that to newsParser, be it instance or local variable, it (newsParser) becomes a pointer to your class' instance.
So if you have to use this newsParser all around your code, best practice is to create an instance variable for it (or even a property) and release it in your class' dealloc method. If you only need it inside one block of code, for example inside init method implementation, just create a local variable and release it right there once you're done with it.
It all depend if you want to expose the instance publicly. If you don't need that, use local variable as you do in the first sample.
If you use the other method, release the instance in the dealloc method of your class.
If you want the instance variable of WebServicesiPhone to have class scope and as VdesmedT said if you want to expose the instance variable publicly.You can hide from exposing it publicly by not declaring it in .h but class extension in .m to have class scope. Release it after you are done with it. Usually in dealloc, but lets say you alloc init this instance in a - (void)createWebService and call it over and over again then dealloc'ing it in dealloc method of class isn't proper memory management.