I have a small question on what super means in xcode. For instance I have the following code. Would it work if i said [super dealloc] first in the dealloc method? Or should super always come last? What exactly is super - I know its the super class but is it the parent class or?
This is the .h file for this class
#interface TwitterTableViewController : PullRefreshTableViewController<TweetDelegate>
This is some code from the .m class for the above interface
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[self.twitterManager release];
[tweets release];
[lastRefreshedLabel release];
[super dealloc];
}
I have checked all over and dont have a satisfactory knowledge yet. If anyone can explain this in laymans terms would be best. thanks
super calls the implementation of the super-class. In your case this would be PullRefreshTableViewController.
Regarding if you should call super before/after your own code, it really depends on what you want to achieve by overriding the method.
In case of dealloc have a look at this question, as Nick Bull mentioned.
The super class can be regarded as a "parent class", yes, if you mean. [super dealloc] calls the implementation of the dealloc method of the super/parent class of the current object (or class, if you call it from a class method).
But, there's no such rule that "super must always come last". The reason why dealloc must always come last is that it destroys the object, so if you accessed your object after it returned, that would crash.
In addition to the existing answers here, the info in this answer may help you in deciding when to call "super".
The methods that are called when the child object/view/viewcontroller is created/initialized, the first thing you do is call the super (i.e., if you want to call it).
When the child object/view/viewcontroller is destroyed/removed, you call the super at the end of the method.
eg:
// methods called when the you are loading/showing with the view controller
-(void)viewDidLoad {
[super viewDidLoad];
//call super and then all your code goes here
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//call super and then all your code goes here
}
// methods called when the you are done with the view controller
- (void)viewWillDisappear:(BOOL)animated{
//all your code goes here and then call super
[super viewWillDisappear:animated];
}
- (void)viewDidUnload {
//all your code goes here and then call super
[super viewDidUnload];
}
Similarly, for -dealloc, the super is called at the end, for -init super is called at the beginning.
Hope this demystifies Super.
super stands for the super object / aka the father of the class you are impementing which extends
in your case is a PullRefreshTableViewController
this kind of behavior is the base of all the object oriented languages, like obj-c.
in the case you are analyzing the super class has a method called
-(UITableviewStyle *) initWithStyle:style
super specifies that the messages should be sent to the parent class (superclass) of the current class. Since you're inheriting from PullRefreshTableViewController, that's where they'll get sent.
super is the parent class, here PullRefreshTableViewController. Calling [super dealloc], which you should always do if you need to implement your own dealloc method, allows your parent class (and its parent class, and so on) to clean up after themselves. It's usually a good idea to perform your own releases, and only then let the parent class do the same, because you can never be sure what the parent class will sweep away from under your feet.
Related
I would like to set a member variable in a derived object before i call [super init].
All I can find is that you should not do such a thing. My worakround, to do it anyhow, works, but actually I like to know what the consequences are when bending the rules. Or even better if there is a correct way to deal with this.
The Details:
I have several wrappers that bind a c++ object to an objective-c objec (mostly UI...View or UI...Controller)
#interface my_scrollview : UIScrollView
{
my_c_class* m_p;
}
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap;
-(void) setContentOffset:(CGPoint)contentOffset;
#end
#implementation dwin_scrollview_ios
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap
{
m_p = pWrap; // illegal but works?
return [super initWithFrame: frame];
//m_p = pWrap; // to late because [super init...] already called overriden func.
}
In my overwritten setContentOffset-method I need to access my C++-Object.
The Problem arises because the initWithFrame internally initializes its content using setContentOffset. So this method is called before I could "legaly" set up the link to my c++-object.
I can implement my overrides with a check if m_p is set(luckily it's initialized to nil). But I have to synchronize the state of the view and my c++-object after the the init-method. In this example this is no big deal but other such realtions are much more complicated and I end up with lot of code that repeats steps of the initialization or otherwise brings me back in sync, although before the [super init...] I know I was in sync.
Is there a pattern to solve this correct (and elegant)?
Is it really so bad to int the pointer before the call to [super init..];?
(I assume one consequence is that this crashes if [super init] returns nil...? any other cases?)
Thanks in advance
Moritz
There is nothing magical about init methods in Objective-C. alloc returns an object of the class that you want, with all instance variables initialized to 0 / nil / NULL / 0.0 etc. Each init method then just executes the code that the developer has written.
There are things that are obviously stupid, like setting an instance variable of the superclass, then calling [super init] which promptly overwrites it. And you need to be aware that init doesn't necessarily return self, but a different object, in which case everything you've initialised in the base class before calling [super init] will be gone.
// illegal but works?
No, it's not illegal. It's perfectly legitimate, although unconventional, to do stuff to an object before its superclass' initializer has been run. It may still lead to unexpected behavior and bugs, but it's not illegal per se. Sometimes it's even necessary, for example when you want to perform some computation and delegate the result of that computation to the superclass' initializer.
You are using wrong init
try this:
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap
{
self = [super initWithFrame: frame];
if (self) {
m_p = pWrap;
}
return self;
}
I have the following method:
- (void) someMethod
{
if ([super respondsToSelector:#selector(someMethod)])
{
[super performSelector:#selector(someMethod)
withObject:nil];
}
}
someMethod does not exist on superclass. as i understand, if there is no such method, runtime will ask the next responder in chain for such method till the NSObject class. And i was sure, that if statement will return NO.
Statement return YES. After that it performs selector without crash. As result - infinite recursion.
so, i have two questions:
Why [super respondsToSelector:#selector(someMethod)] returns YES ?
Why [super performSelector:#selector(someMethod) withObject:nil] does not crash with error 'does not responds to selector' ?
I think i've missed something essential.
Please, help.
Yes, you missed something essential as you suggest. From the documentation for respondsToSelector:
You cannot test whether an object inherits a method from its superclass by sending respondsToSelector: to the object using the super keyword. This method will still be testing the object as a whole, not just the superclass’s implementation. Therefore, sending respondsToSelector: to super is equivalent to sending it to self. Instead, you must invoke the NSObject class method instancesRespondToSelector: directly on the object’s superclass, as illustrated in the following code fragment.
if( [MySuperclass instancesRespondToSelector:#selector(aMethod)] )
{
// invoke the inherited method
[super aMethod];
}
HTH
I spent much time to get a better understanding in delegation in Objective-C. I got it working for most cases, but there is a problem in a specific case, which I find difficult to understand. Let me explain what I am trying to do:
I have a custom view called GridLayoutView, which is subclass of UIView. I also have a view controller SomeViewController, which is the delegate of GridLayoutView.
I have a custom initWithFrame method, and I am conditionally calling another initialization method baseInit. That method calls a delegate method at some time. Here is some code from GridLayoutView:
//
// Delegator
// GridLayoutView.m
//
#implementation GridLayoutView
- (id)initWithFrame:(CGRect)frame
numberOfRows:(NSUInteger)rows
numberOfCols:(NSUInteger)cols
{
self = [super initWithFrame:frame];
if (self) {
self.numberOfRows = rows;
self.numberOfCols = cols;
self.numberOfCells = rows * cols;
if (self.numberOfCells > 0) [self baseInit];
}
return self;
}
- (void)baseInit
{
// do some more initialization stuff here
// ...
// then call a delegate method
[self.delegate someMethod:someObj];
// However, this method is not called because self.delegate is nil
}
and some code from SomeViewController:
//
// Delegate
// SomeViewController.m
//
#implementation SomeViewController
// ...
// in some method
self.gridLayoutView = [[GridLayoutView alloc] initWithFrame:gridLayoutFrame
numberOfRows:rowsCount
numberOfCols:colsCount];
self.gridLayoutView.delegate = self;
// ...
The delegate method never gets called within baseInit, because the delegate is nil at that time and it gets set after initWithFrame and baseInit methods are done. I have confirmed this.
I sense that there is something wrong in my workflow of delegation. I have a solution but I don't think it is the best way to go. The solution is basically passing the SomeViewController instance to the delegator by modifying the initWithFrame method such as:
- (id)initWithFrame:(CGRect)frame
numberOfRows:(NSUInteger)rows
numberOfCols:(NSUInteger)cols
delegate:(id<GridLayoutViewDelegate>)aDelegate
This approach works, but I am uncomfortable due to passing SomeViewController to GridLayoutView in its initWithRect. I am wondering if this is a good way to go with delegation or is there a better approach? I would be very grateful if someone can clear this for me.
If I'm understanding you correctly, there aren't many options here.
Modifying your initializer (as you suggested) to pass in the delegate. There is nothing wrong with that, don't know why you don't like it.
Remove the dependency on the delegate during initialization and instead, send whatever delegate message is appropriate when the delegate property is set by overriding the setter:
- (void)setDelegate:(id<GridLayoutViewDelegate>)aDelegate
{
_delegate = aDelegate;
// send whatever message makes sense to the delegate
[_delegate someMethod:object];
}
EDIT - noticed your comment
Your initialization method should not take any significant amount of time. It's unclear what you mean by 'loading views'. If you simply mean creating and adding subviews to a view then that is fast and there should be no need to communicate progress to a delegate (which you can't do anyway b/c the initialization is on the main thread and UI won't update until all of init is complete).
If you mean loading data that takes a long time, you should disconnect that from initialization and load the data in a background operation, sending progress messages to a delegate.
i would implement the setDelegate function and then call
[self someMethod:someObj]; from there
Is there a method that is always called in Cocoa? Many classes have init or initWith, but even worse they can be loaded from a nib or something. I don't want to have to scrape around and find how it does this in this case. I just want to set some initial variables and other things, and I want a method to subclass that I can depend on no matter if it's a UIView, UIViewController or UITableViewCell etc.
No there is not such a method. init comes from NSObject so every object can use it, and as well subclasses define their own initialization methods. UIView, for example, defines initWithFrame: and furthermore there are init methods from protocols, such as NSCoding which defines initWithCoder:. This is the dynamic nature of objective-C, anything can be extended at any time. That being said, there are some patterns. UIViewController almost always takes initWithNibName:bundle: and UIView almost always takes initWithFrame: or initWithCoder:. What I do is make an internal initialize method, and just have the other inits call it.
- (void)initialize
{
//Do stuff
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initialize];
}
}
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if(self)
{
[self initialize];
}
}
Not 100% sure that it is always called, but I am pretty sure that this is a viable option. To be perfectly honest, I can't recall that I have ever seen this method used in practice and I usually shy away from using this method (I have absolutely no idea why, probably because it's just not the cleanest and most comprehensive method to achieve this...):
-didMoveToSuperview()
From documentation:
Tells the view that its superview changed.
The default implementation of this method does nothing. Subclasses can override it to perform additional actions whenever the superview changes.
There's many ways you can write a custom initializer.
- (id)initWithString:(NSString *)string {
if((self == [super init])) {
self.string = string;
}
return self;
}
That's just how I write my initializers in general. For example, the one above takes a string. (you don't have to pass strings if you don't want).
Btw, init is a method. According to the header for NSObject, init has a method implementation.
I want' to implement "Fix and continue functionality" that was in Xcode 3.
CONTEXT:
The main idea is:
When I need to "Fix something fast", I'm not re-compiling, project. I'm compiling small Attacker class with 'updated' method implementation, loading it into memory and replacing VictimClass's method which have incorrect implementation in runtime.
I think that this method will work faster that full project recompilation.
When i'm done with fixes i'm just copying source of Attacker class method to Victim class.
PROBLEM
At the moment, I don't know how correctly call [super ...] in Attacker class.
For example, i have VictimClass
#interface VictimClass : UIView #end
#implementation VictimClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
#end
#interface AttackerClass : NSObject #end
#implementation AttackerClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[self setupPrettyBackground];
}
#end
....
// EXCHANGE IMPLEMENTATIONS
Method m = class_getInstanceMethod([AttackerClass class], #selector(drawRect:));
const char * types = method_getTypeEncoding(m);
IMP attackerImp = method_getImplementation(m);
class_replaceMethod([VictimClass class], #selector(drawRect:), attackerImp, types);
// Invoking drawRect on Victim
VictimClass * view = /* */;
[view setNeedsDisplay];
At this point , when drawRect: method will be called, this will lead to exception, since drawRect: will be called on NSObject class, but not on UIView class
So, my question is, how correctly call [super drawRect:] in AttackerClass, to have possibility to correctly exchange implementation in runtime?
Main idea is to provide a way to correctly replace any method in Victim class by Attacker's class method. Generally, you don't know, superclass of Victim class.
UPDATE: Replacing implementation code added.
You will have to
get the receivers class (e.g. with object_getClass(rcv))
then get the super class of it (with class_getSuperclass(class))
then get the implementation of it (with class_getMethodImplementation(superclass, sel))
then call the imp.
done
Stop at any step if you got nil or NULL.
Oh, and all this seems silly. But I assume that the question just lacks of context to see the motivation for such a hack.
[Update]
An explanation for future readers:
The super keyword is resolved at compile time. Therefore it does not the intended thing when changing methods at runtime. A method which is intended to be injected in some object (and its class hierarchy) at runtime has to do super calls via runtime as outlined above.
Assuming that the runtime changes you're making involve modifying the superclass, you'll have to do something like this:
#implementation AttackerClass
-(void) drawRect:(CGRect)rect
{
if( [super respondsToSelector:#selector(drawRect:)] )
{
[super drawRect:rect];
}
[self setupPrettyBackground];
}
#end
This will check if the superclass "knows about" drawRect:, and doesn't call it in the case that super has no drawRect: selector.
Hence, when the superclass is NSObject the drawRect: message will not be sent. When you change it to UIView at runtime (whatever your reason for that is), the message can safely be sent.
One approach is to use objc_msgSendSuper. Your method -[AttackerClass drawRect:] will have the following implementation:
- (void)drawRect:(CGRect)rect {
struct objc_super superTarget;
superTarget.receiver = self;
superTarget.class = object_getClass(self);
objc_msgSendSuper(&superTarget, #selector(drawRect:), rect);
[self setupPrettyBackground];
}
but why do you need to call draw rect method for superclass NSObject, when NSObject hasn't got that method? just don't do it... call it just in VictimClass drawrect