Ok, this is going to be a really embarrassing question, but I looked like mad in my beginner's books (especially those usually helpful indices) and behold, I did not find a down-to-earth explanation of what 'super' does in my applications.
I had a look at this here, but I'm afraid that's well beyond me. Can anyone offer a very simply explanation of what 'super' does in my apps and why I should become friends with it? E.g.:
- (void)viewDidLoad {
[super viewDidLoad];}
Thanks!!
super calls the superclass's implementation of the method. So if your class inherits UIViewController, then [super viewDidLoad]; will call the UITableViewController class's viewDidLoad method. You should usually do this because the super class may do important things that need to happen. In the case of viewDidLoad, I'm not sure it actually does anything currently, but it always could in a future version of the framework.
at the low level, self contains a pointer to the set methods it responds to. this is a basic mechanism for the implementation of dynamic dispatch. each class is given a unique set. if you're familiar with c++, this is similar in concept to a virtual table. you can think of an objc method as being like a C function with 2 hidden arguments (self,_cmd).
super is a dynamically created representation of self, with a pointer to the next-in-line methods implemented by the instance's superclasses. this representation is based on self, and just directs to another set of implemented methods.
#interface MONTypeA : NSObject
- (void)monMethod;
#end
#interface MONTypeB : MONTypeA
- (void)monMethod;
#end
#implementation MONTypeA
- (void)monMethod {
printf("i am MonTypeA\n");
}
#end
#implementation MONTypeB
- (void)monMethod {
[super monMethod]; /* << will call -[MONTypeA monMethod], which will print "i am MonTypeA\n" */
printf("i am MonTypeB\n");
}
#end
if you create an instance of MONTypeA, then it will respond to monMethod:
MONTypeA * a = [MONTypeA new];
[a monMethod];
[a release], a = 0;
// outputs: "i am MonTypeA\n"
MONTypeB * b = [MONTypeB new];
[b monMethod];
[b release], b = 0;
// outputs: "i am MonTypeA\n""i am MonTypeB\n" because -[MONTypeB monMethod] calls through super
therefore, calling super performs the implementation of the method of the superclass in this specific case.
it is important to remember: the set of methods super refers to is always those of the previous implementation of the method in the hierarchy, it is not the same set as the set of instance methods which an instance of the superclass would be given (unless your class were to override every method).
Related
A very basic question on how to interact between classes here: how can I trigger an action called by clicking on a button linked to one class (the graphic user interface in my case - which does not contain any drawing code) inside another class (my drawing class - which is defined programmatically)?
Thanks!
Edited: I have tried to implement the solutions suggested below but I didn't manage to trigger the action from the other class. I have two classes: the main view controller and a class with the drawing code. Any advice would be highly appreciated. Thanks!
//MainViewController.m
//This class has a xib and contains the graphic user interface
- (void)ImageHasChanged
{
//do something on the GUI
}
//DrawView.m
//This class has no associated xib and contains the drawing code
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//I want to call ImageHasChanged from MainViewController.m here
//How can I do this?
}
Inter-class functionality is done simply by importing one class into the other, and calling an accessible method/instance variable on the import.
For the button IBAction example in your question:
ClassA.m (This will be imported via its header):
#import "ClassA.h"
#implementation ClassA
// This is a class-level function (indicated by the '+'). It can't contain
// any instance variables of ClassA though!
+(void)publicDrawingFunction:(NSString *)aVariable {
// Your method here...
}
// This is a instance-level function (indicated by the '-'). It can contain
// instance variables of ClassA, but it requires you to create an instance
// of ClassA in ClassB before you can use the function!
-(NSString *)privateDrawingFunction:(NSString *)aVariable {
// Your method here...
}
#end
ClassB.m (This is your UI class that will call the other method):
#import "ClassA.h" // <---- THE IMPORTANT HEADER IMPORT!
#implementation ClassB
// The IBAction for handling a button click
-(IBAction)clickDrawButton:(id)sender {
// Calling the class method is simple:
[ClassA publicDrawingFunction:#"string to pass to function"];
// Calling the instance method requires a class instance to be created first:
ClassA *instanceOfClassA = [[ClassA alloc]init];
NSString *result = [instanceOfClassA privateDrawingFunction:#"stringToPassAlong"];
// If you no longer require the ClassA instance in this scope, release it (if not using ARC)!
[instanceOfClassA release];
}
#end
Side note: If you're going to require ClassA a lot in ClassB, consider creating a class-wide instance of it in ClassB to re-use wherever it's required. Just don't forget to release it in dealloc (or maybe set it to nil in ARC) when you're finished with it!
Finally, please consider reading through the Apple Docs on Objective-C classes (and indeed all other sections of the documentation relevant to what you're trying to achieve). It is a bit time-consuming, but very well invested in the long run into building your confidence as an Objective-C programmer!
//As you said an instance of MainViewController has to be created first
MainViewController *instanceOfMainViewController = [[MainViewController alloc]init];
[instanceOfMainViewController ImageHasChanged];
//Thanks for your help Andeh!
Actually you can use #protocol(Delegate) to interact message between two classes this is standard way Or refer this document
http://developer.apple.com/library/ios/#documentation/General/Conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html to learn more
just had a noob question. I'm trying to understand the difference between calling self and super. Now I understand inheritance and other fundamental OOP concepts, but the idea of self and super is still not clear to me. I'll illustrate my question with an example.
So the the below code performs a segue when the phone is tilted upside-down. I understand that "Scene2ViewController" is a subclass of "UIViewController" and so "Scene2ViewController" inherits all of UIViewController's methods. And so below I'm calling the method performSegueWithIdentifier with the receiver of the message being self. Now when I change "self" to "super" the code still executes the same way. Isn't calling super the same as calling self? If someone could explain this to me it would be appreciated, thanks.
//Scene2ViewController.m
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
[self performSegueWithIdentifier:#"SegueToScene1" sender:self];
}
return (interfaceOrientation ==
UIInterfaceOrientationPortrait);
}
self and super actually both point to the same object. super is a keyword that tells the compiler to generate instructions that start the search for a method definition in the super class rather than in the current class.
#interface A : NSObject {}
- (void)foo;
#end
#implementation A
- (void)foo {
NSLog(#"A's foo!");
}
#end
#interface B : A
#end
#implementation B
- (void)foo {
NSLog(#"B's foo!");
}
#end
//...somewhere in a method of class B...
[self foo]; // prints "B's foo" in the console
[super foo]; // prints "A's foo" in the console
If we assume, per the comment, that the last lines are somewhere in a method of B, then self points to some instance of B. super also points to that same instance of B. But when you use self to call foo, the search for an implementation of foo starts with class B. When you use super, the search for a foo starts with B's superclass, A.
super is especially handy when you want to preserve the inherited behavior, but add something on. So, we could have B's implementation of foo call A's version using [super foo]. Without super there'd be no way to call the inherited method, and calling foo from the overridden method would result in infinite recursion.
When you call a method of self (or rather send a message to self in Objective-C terms) the runtime will search for an implementation of that method in the inheritance hierarchy, starting with self, going up to NSObject. So if self implemented that method, it will be executed. If not, the super class will be checked and so on.
Sending the message to super is very similar, with the exception that the runtime will start looking for an implementation in super and skip self.
Well sometimes, in a subclass, you might override a function that was already defined in the parent class. Frequently this happens in the init function. So if you need to call the parent class's init function you call super. If you need the subclass' function you call self. If only the parent has the function declared then Self and super act the same. But if only the subclass has the declaration then you cannot call the function from super.
i have some trouble writing a method in Objective-C to make an object nil. Here is some example :
#interface testA : NSObject
{
NSString *a;
}
#property (nonatomic, retain) NSString *a;
+(testA*)initWithA:(NSString *)aString;
-(void)displayA;
-(void)nillify;
#end
#implementation testA
#synthesize a;
+(testA*)initWithA:(NSString *)aString{
testA *tst=[[testA alloc] init];
tst.a=aString;
return [tst autorelease];
}
-(void)displayA{
NSLog(#"%#",self.a);
}
-(void)nillify{
self=nil;
}
- (void)dealloc {
[a release];
[super dealloc];
}
#end
int main(int argc, char **argv){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
testA *test=[testA initWithA:#"some test"];
[test displayA];
test=nil;
//[test nillify];
NSLog(#"after setting to nil");
[test displayA];
[pool release];
return 0;
}
Apparently , when I set test object to nil and then call some method on it nothing happens , but if i call nillify instead of directly setting it to nil , displayA method works normally like test object is still there. Is there a workaround for nillify method to function properly ?
Your help is much appreciated !
You can't actually do something like this, because setting 'self' to nil only has any effect within the scope of that method (in your case, 'nilify'). You don't have any actual way to effect the values of pointers located on other parts of the stack or in random places in the heap, for example.
Basically any code that holds a reference to some object is responsible for maintaining and clearing those references itself. If you have some use case where random sections of code may need references to "live" objects of some kind, but where you'd want those object references to go away in response to some external event (maybe a user tracking system or something), you could do something with notifications, but the various modules tracking those "live" objects would still be responsible for listening for notifications and cleaning up references when they received them.
The 'nilify' thing, however, can't possibly work.
You cannot do what you're trying to do. self is just a local reference to an object that actually exists elsewhere. Setting it to nil doesn't mean anything. An object doesn't, in general, own itself, and it certainly doesn't control other objects' references to it. It's up to the owning objects to manage its lifetime.
There are a few things wrong with your code.
First, by convention, class names start with an uppercase letter. Please stick to these naming conventions as it will make it harder for other developers to work with your code (and even confuse you).
Next, your initWithName:... According to the naming conventions, a method with init in its name should be an instance method, not a class method. So either name it newWithName: or turn it into an instance method like this:
-(testA*)initWithA:(NSString *)aString{
self = [super init];
if (!self) return nil;
tst.a=aString;
return self;
}
If you keep it as class method (and name it newWithName:) you should not return a autoreleased object since according to the naming conventions method that start with init... or new... return a retained object. If you do not follow these conventions, the static analyzer will give you "false" warnings and it will become useless for you.
Now for the reason your nillify doesn't work: the self is in fact an argument to a method. Under the hood, your nillify method actually has two arguments that you do not see: the self pointer and the selector pointer. This means, self is actually a variable on the stack. And if you overwrite it, you only overwrite that stack variable but that doesn't influence your test variable which is somewhere else.
As an example, consider a method - (void)foo:(NSString *)bar;. The compiler turns it into the equivalent of the C function (void) foo(id self, SEL _cmd, NSString *bar).
I am trying to get my head round Objective-C Protocols. I have looked at the Apple docs and also relevant chapters in a couple of books that I own, but nearly always protocols seem to be defined in terms of using them as in interface to delegate objects. I understand the concept of creating the protocol definition:
#protocol PetProtocol <NSObject>
- (void)printCat;
- (void)printDog;
#end
I also understand the bit where I conform a class to a protocol:
#interface CustomController : UIViewController <PetProtocol> {
followed by implementing the required methods.
#implementation CustomController
- (void)printCat {
NSLog(#"CAT");
}
- (void)printDog {
NSLog(#"DOG");
}
I guess my question is how to use this protocol, it seems a bit strange to call, printCat and printDog from CustomController where the methods are implemented, can anyone point me at or give me a really simple example of using this protocol or similar?
much appreciated
gary.
A protocol is just a list of messages that an object can respond to. If an object conforms to a protocol, it's saying, "I respond to these messages." This way, you can return an object that the caller can use without having to promise that the object will be of any particular type. For example, with that protocol, you could do this:
id<PetProtocol> getSomeObjectThatConformsToThePetProtocol() {
return [[[CustomController alloc] init] autorelease];
}
int main() {
id<PetProtocol> foo = getSomeObjectThatConformsToThePetProtocol();
[foo printCat];
[foo printDog];
return 0;
}
See, main() doesn't need to know that the object is a CustomController — it just knows what messages you can send the object. Any class that conforms to PetProtocol would do. That's what protocols are for.
Protocol (or delegation) is used to call a method in a different class. For example, the class that contains the protocol (lets call it PetClass) would call [self.delegate printCat] and the delegated class (CustomController) would carry that method out for the PetClass object.
This might help as well:
delegation: the assignment of
authority and responsibility to
another person (normally from a
manager to a subordinate) to carry out
specific activities
This assumes of course you have defined self.delegate in your header and synthesized it in your implementation:
Header iVars:
id <PetProtocol> delegate;
Implementation:
#implementation PetClass
#synthesize delegate;
When implementing an +initialize or +load method in one of your Objective-C classes, should you always start with this kind of guard?:
#implementation MyClass
+ (void)initialize {
if (self == [MyClass class]) {
...
}
}
...
#end
Seems like code in +load and +initialize usually only wants to be executed once. So this would help avoid dupe execution when subclasses load/initialize.
I guess I'm just wanting some reinforcement from some ObjC wizards that this is necessary/common practice...
What's the common wisdom on this? would you recommend always doing this?
Is your advice the same for both +load and +initialize, or is there a difference in they way they should be handled?
thanks.
The quick answer is: No.
An in-depth discussion of this matter can be found on the Apple developer mailing list.
The gist of it is that:
The runtime will actually call +initialize on super classes before it is called on subclasses.
If you do include the guard, subclasses of your class that have their own +initialize method will not trigger dependent KVO notifications.
For an example of point #2, be sure to read this post in the thread mentioned above.
Yes, you should do this in your intialize and load methods if you are initializing globals that should only be initialized once.
That said, there are a number of cases where you may avoid it...
You shouldn't wrap with this conditional if the work needs to be performed on every inheritant of every class:
For example, adding all inherited class names for each class to a set.
edited addition: or you're establishing KVO dependencies (as mentioned by eJames)
There are also situations where you just needn't bother:
If the actions you perform are idempotent (don't change values if repeated)
The class is "sealed" (has no descendants by design)
The "idempotent" part is relevant. An initializer should just be setting the initial state (which should be the same each time). In a good initializer, repetition shouldn't matter. Although I suppose that if you forget to wrap the method in the conditional when it does matter, this might be annoying.
edited addition: A different approach, that properly reflects any initialize-only-once requirements would be to test if your properties to initialize are initialized already. i.e.
id myGlobalObject = nil;
+(void)initialize
{
if (myGlobalObject == nil)
{
myGlobalObject = [[MyGlobalClass alloc] init];
}
}
YES!!!!
Because the initialize method of a class may be invoked many times. e.g. when you implement initialize in parent class, and don't implement in sub class, then you call sub class first, the initialize of parent will invoked twice.
#implementation BaseClass
+ (void)initialize
{
NSLog(#"BaseClass initialize self=%#, class=%#", self, [BaseClass class]);
}
#end
#interface SubClass : BaseClass
#end
#implementation SubClass
// don't implement the initialize method
#end
==================
now when you call SubClass first, just like
[SNSBaseSubLogic alloc]
look the debug console, output:
BaseClass initialize self=BaseClass, class=BaseClass
BaseClass initialize self=SubClass, class=BaseClass
so, you must use
+ (void)initialize
{
if (self == [BaseClass class]) {
NSLog(#"BaseClass initialize self=%#, class=%#", self, [BaseClass class]);
}
}
to ensure the method body execute once.