I have a method with an id parameter in it. I also have an id as a property inside my class. My question is in the init method is there a way I can determine if the passed parameter can be retained so I can do something like:
someProperty = [idParameter retain];
Thanks
All Objective-C objects (i.e. anything inheriting from the NSObject class or implementing the NSObject protocol) implement retain. It's implemented by the NSObject class and it's a required method for the protocol, so you cannot have an Objective-C object that you cannot call retain on.
The only time you'd not be able to call it in these circumstances is if your variable of type id was not pointing to an Objective-C object. This would be a mistake, do not do this.
Every object that inherits from NSObject has a respondsToSelector: method. (Documentation)
Therefore, you could write:
if ([idParameter respondsToSelector:#selector(retain)])
someProperty = [idParameter retain];
Related
retain is declared in NSObject protocol.
Therefore NSObject class and NSProxy class implement it.
yet both NSProxy and NSObject classes both have an alloc.
Why isnt alloc declared in NSObject protocol?
Side question:
NSObject protocol is also used to stored the class version of a method where as the instance method is in NSObject class. Is there anything to stop both class and instance being declared in the NSObject protocol. Why split them up?
#protocol NSCopying
- (id)copyWithZone:(NSZone *)zone; //INSTANCE METHOD version of copyWithZone
#end
#interface NSObject <NSObject> {
Class isa;
}
...
+ (id)copyWithZone:(NSZone *)zone; //CLASS METHOD version of copyWithZone
Cheers
I think this is determined by what is required by Objective-C, and what is required by implementation.
In order to create an object, you need a way to allocate it. This is done by the alloc method. Since this is required to use objective-c, it is implied that all root objects should implement it. However, memory management does not have to be done through reference counting. You could use garbage collection instead. Because of this, the retain method is not required to use objective-c. Apple's implementation created the retain method as a form of memory management. They wanted to ensure that all objects had it available, so they added it to the NSObject protocol. All root classes in Cocoa are supposed to conform to that protocol, so they should all have a retain method.
A class can conform to the NSCopying protocol to show that instances of that class can be copied. Normally, you wouldn't want to copy a class, so a class method isn't defined there. However, sometimes you don't know whether an object is a class or instance, but calling conformsToProtocol: will return the same value either way. By making an identically named class method, you know that it is safe to call copyWithZone: even if you don't know whether you have an instance or class.
As an Objective-C beginner, I'm very confused about the init function, and how and when to override it. So here are few questions :
Apparently, it works fine when the init function is not overridden, so is it just a good practice to do it? If it is, then is it a very bad practice not to do it?
Let's assume I'm overriding the function because I have to assign a default value to a variable. Do I have to allocate and initialize all the other ivars, including IBOutlets?
Please note I'm aware of the syntax :
if ((self = [super init]))
{
_foo = [[Bar alloc] init];
}
return self;
Per "Initialization":
A class generally implements an initializer for its objects, but is not required to. If a class does not implement an initializer, Cocoa calls the initializer of the nearest ancestor of the class. However, subclasses often define their own initializer or override an initializer of their superclass to add class-specific initializations. If a class does implement an initializer, it should invoke an initializer of its superclass as the first step. This requirement ensures a series of initializations for an object down the inheritance chain, starting with the root object. The NSObject class declares the init method as the default object initializer, so it is always invoked last but returns first.
As this says, you override your superclass's designated initializer when you need to do some initialization after it's done with its initialization. Don't need to do that? Then you don't need to override.
When your object is instantiated from a NIB, -init is not called. Instead, your newly allocated object will receive an -initWithCoder: or -initWithFrame: message depending on the object's type. The NIB loading process sends your object -awakeFromNib after it and all the other NIB-created objects it references have been established. This lets you avoid overriding -initWithCoder:/-initWithFrame: when you wish to do some configuration after the NIB has been loaded. If you can do what you want to do by overriding -awakeFromNib rather than an initializer, you should do that.
See also "Multiple Initializers", which explains the "designated initializer" concept and how different classes can have different designated initializers, and "Allocating and Initializing Objects" for a less friendly but more in-depth description of the allocation and initialization conventions adopted by Objective-C.
There is no need to override -init (or the designated initializer) unless you need to do class-specific initialization.
You do not need to (nor should you) allocate or initizlize IBOutlets. Objective-C will automatically initialize all instance variables including IBOutlets to 0 (nil).
no not at all .... just initialize what ever you want ... again IBOutlets are not initialized ... you only set them to nil when there is a memory warning or when ever you want to break the link ....
I have an object that belongs to a class. Lets call it classA. This classA is a subclass of classB.
ClassA has a delegate protocol.
I create an classA object on my main code. This object is inside a view. Lets call it viewX.
Now I am in classB and I would like to get a reference to viewX.
remember that classA has a delegate protocol, so it has a reference to its delegate, that is the viewController where viewX is. From class A I can access viewX doing [delegate view], but how do I do that from classB???
thanks.
If you have access to class B, I would say you should add a variable to the class of type id, and set that variable as the view, and that would be a very easy way to do it. Otherwise, I don't think it's possible. But I may be wrong.
Can you explain "An instance method you define in a category of the NSObject class might be performed not only by instances but by class objects as well", i have come across this sentence while reading an Objective C guide...! But i am not able to get it.
Instance method is a method you can call on an object (as opposed to a class). Each object is an instance of a certain class (just as each of us is an instance of a human1), that’s why we talk about instance methods. For example when you say [someArray count], you are calling an instance method called count on some array object (= instance of the NSArray class).
Class methods are called on classes, for example [UIApplication sharedApplication] is a class method of the UIApplication class. You can’t call an instance method on a class, nor can you call a class method on an object.
Category is a way to extend behaviour of existing classes, a kind of plugin you stick on an existing class. For example by writing this:
#interface NSObject (SampleCategory)
- (void) sayFoo;
#end
#implementation NSObject (SampleCategory)
- (void) sayFoo {
NSLog(#"Foo!");
}
#end
…you make it possible to call [anObject sayFoo] on any object derived from NSObject. And now we are getting to the point of the sentence: NSObject seems to be special, because when you declare an instance method of NSObject using a category (such as our sayFoo), you can call this method even as a class method: [NSObject sayFoo], [NSView sayFoo], etc.
1] Sorry, Googlebot!
I have several dataSources I use for one UIViewController. My view controller uses KeyValue Observing in order to follow the state of certain properties at runtime. When I swap dataSources, I need to stop observing those properties. The problem is, I'm not sure of the class of the dataSource at runtime, therefor something like this is not valid:
if (aDataSource != dataSource) {
// Ensure we stop observing the existing dataSource, otherwise bad stuff can happen.
[dataSource removeObserver:self forKeyPath:#"someKeyPath"]; // not valid, compiler doesn't know what class dataSource is.
[dataSource release];
dataSource = [aDataSource retain];
}
The compiler needs a concrete class in order to know the object's interface. How can I grab the class of dataSource in this particular case, and then typcast the dataSource for the removeObserver:forKeyPath: selector above? I prefer something dynamic/smarter than caching the name of the class in an NSString instance and referring to that whenever I switch. Meaning, I could always do something like:
NSString *lastDataSource = #"MyClass";
Class foo = [NSClassFromString(lastDataSource)];
Thanks.
If you code like this:
id foo = ...;
[foo removeObserver:self forKeyPath:#"someKeyPath"];
The compiler will be fine with it as objects with type id accepts any message (as long the signature is known to the compiler).
Now if you have:
id<NSObject> foo = ...;
[foo removeObserver:self forKeyPath:#"someKeyPath"];
The compiler will give you a warning:
warning: '-removeObserver:forKeyPath:' not found in protocol
This is because you're referring to the protocol NSObject not to the NSObject class where the KVO methods are defined.
But if you have:
NSObject* foo = ...;
[foo removeObserver:self forKeyPath:#"someKeyPath"];
That will compile fine too, as in this case you're using the class NSObject.
Related links:
Objective-C protocol
The id Type and Protocols
What do you mean it is not valid? Do you get a compile error?
Objective-C supports dynamic typing for objects by default. You should be able to call any method on any object in Objective-C, even if the compiler can't guarantee from the static type that that object supports that method.
I think you need to cast them to NSObject *, since that's where the KVO methods are (not in NSObject protocol).
Just let me add that the approach you outline with ...
NSString *lastDataSource = #"MyClass";
Class foo = [NSClassFromString(lastDataSource)];
... will of course not be able to supress your compile-time warnings, since the class "foo" will only get calculated at run-time. So even though you as the programmer can plainly see from the code that "foo" will end up being the class "MyClass", this is not clear to the compiler, and so if "MyClass" has a method "myMethod:" you will still get a compiler warning if you send that message to an object declared as "foo".
I'm guessing you realise this, but it's better to make it clear why that approach won't solve your problem.