how to initialize an object of subclass with an "existing object of superclass" in objective-C - objective-c

I have subclassed NSException class to create CustomException class.
Whenever I catch an exception in code (in #catch), i want to initialize an object of CustomException (subclass of NSException) with the object of NSException that is passed as a parameter to #catch.
Something like this
#catch (NSException * e) {
CustomException * ex1=[[CustomException alloc]initWithException:e errorCode:#"-11011" severity:1];
}
I tried doing it by passing the NSException object to the init method of CustomException.
(i replaced the [super init] with the passed NSException object as given below)
//initializer for CustomException
-(id) initWithException:(id)originalException errorCode: (NSString *)errorCode severity:(NSInteger)errorSeverity{
//self = [super initWithName: name reason:#"" userInfo:nil];
self=originalException;
self.code=errorCode;
self.severity=errorSeverity;
return self;
}
This doen't work! How can I achieve this?
Thanks in advance

You are trying to do something which generally[*] isn't supported in any OO language - convert an instance of a class into an instance of one of its subclasses.
Your assignment self=originalException is just (type incorrect) pointer assignment (which the compiler and runtime will not check as you've used id as the type) - this won't make CustomException out of an NSException.
To achieve what you want replace self=originalException with
[super initWithName:[originalException name]
reason:[originalException reason]
userInfo:[originalException userInfo]]
and then continue to initialize the fields you've added in CustomException.
[*] In Objective-C it is possible in some cases to correctly convert a class instance into a subclass instance, but don't do it without very very very very good reason. And if you don't know how you shouldn't even be thinking of it ;-)

self = originalException;
When you do that you are just assigning a NSException object to your NSCustomException so
the following things will happen:
You might get a warning when doing
the assignment since
CustomException is expected but you
are passing just a NSException
object ;(
After that, the compiler will think that self
is a CustomException object so it
won't complain when calling some
methods of CustomException class
but it will crash when reaching
those.
You should enable initWithName:reason:userinfo: and don't do the assignment.

Related

Why a pointer to no object can be asked to execute a setter?

I creating a pointer does not create a Class object.
But it can be send method to execute in another instance method.
I think just a pointer to the object can be asked to execute a method.
Why the "t" can use setter in the method like this image?
This happens because Xcode only checks if declared type of t variable has visible readwrite property named a. It doesn't care if t is actually object or something else at this point. For example, it cannot know if t is object or nil, or anything else in such situation
- (void) method:(One*) t{
t.a = #"Some string";
}
You can call it like this
[two method:nil];
Xcode won't complain. You can even do this
One *t = (One *)[[NSObject alloc] init]; //warning here
t.a = #"Some t"; //Xcode doesn't care, that t is actually NSObject and doesn't respond to setA:; But you get a runtime error
nil in ObjC responds to all selectors - you can call any visible method on nil object and you won't get a warning nor error. Just silently passes by

Can you define a Class (objc_class) parameter to have a required subclass at compile time?

I have the following method:
- (FDModel *)_modelForClass: (Class)modelClass
withIdentifier: (NSString *)identifier
which should take in a Class and a identifier, create an instance of modelClass, assign the identifier and do some other work based on the fact that it assumed modelClass is a subclass of FDModel.
I can put in a check that raises some error or exception if [modelClass isSubclassOfClass: [FDModel class]] == NO but I was trying to see if there was a way to enforce this at compile time.
EDIT: I understand that some people see this as a obvious factory method but the modelClass parameter is actually passed in by the user of my library through a delegate callback - (Class<FDModel>)modelClassForDictionary: (NSDictionary *)dictionary;. This question was more aimed at making the user of my library return a Class that has a specific subclass.
I would consider the plain answer to your question being no; there is no way of checking if a class passed as a parameter is of a certain kind.
But I'd like to argue that the essence of your question primarily points to a design issue, i.e. can't your instance-generating method be expressed as a factory method? Like so:
#interface FDModel
+ (instancetype)modelWithIdentifier:(NSString *)identifier;
#end
In the above case you would simply do:
[FDModel modelWithIdentifier:anIdentifier];
The actual class returned (and the initialisation logic) being specified by the factory method implementation through subclassing of the FDModel class:
#implementation FDModelSubclass
+ (instancetype)modelWithIdentifier:(NSString *)identifier
{
FDModel *model = [super modelWithIdentifier:identifier];
if (model)
{
// do additional init stuff
}
return model;
}
#end
Nothing to check, no chance to go wrong.
After some research I don't think you can do it at compile time - you have to do it at runtime as you expected.
BOOL classConformsToProtocol = [class conformsToProtocol:#protocol(OKAProtocol)];
OR
BOOL classConformsToProtocol = [self class:[OKAClass class] conformsToProtocol:#"OKAProtocol"];
------
- (BOOL)class:(Class)class conformsToProtocol:(NSString *)protocol;
{
return [class conformsToProtocol:NSProtocolFromString(protocol)];
}

Why is it that sending any selector to a Nil object does nothing, but sending an "invalid" selector to any NSObject raises an exception?

Does anyone know why NextStep/Apple decided to take the "convenient method" of doing nothing when passing a Nil object a message, but the "Java method" of raising an exception when passing an instantiated object an invalid selector?
For example,
// This does "nothing"
NSObject *object = Nil;
[object thisDoesNothing];
object = [[NSObject alloc] init];
// This causes an NSInvalidArgumentException to be raised
[object thisThrowsAnException];
So on one hand, we have the convenience of not having to check for Nil (assuming we don't care too much about the result of the method call)--but on the other hand we have to check for an exception if our object doesn't respond to a method?
If I'm not sure if the object will respond, I either have to:
#try {
[object thisThrowsAnException];
} #catch (NSException *e){
// do something different with object, since we can't call thisThrowsAnException
}
Or,
if([object respondsToSelector:#selector(thisThrowsAnException)]) {
[object thisThrowsAnException];
}
else {
// do something different with object, since we can't call thisThrowsAnException
}
(The latter is probably the better way to do it, since if object is Nil, the selector would NOT raise an exception, thus your code might not behave the way you want it to).
My question is:
WHY did Apple decide to implement it this way?
Why not have the unrecognized selector call to an instantiated object not raise an exception?
Alternatively, why not have the Nil object raise an exception if you try to call a method on it?
I can't fully answer your question, but I can answer part of it. Objective-C allows you to send a message to nil because it makes code more elegant. You can read about this design decision here, and I will steal its example:
Let's say you want to get the last phone number that some person dialed on her office phone. If you can't send messages to nil, you have to write it like this:
Office *office = [somePerson office];
// Person might not have an office, so check it...
if (office) {
Telephone *phone = [office telephone];
// The office might not have a telephone, so check it...
if (phone) {
NSString *lastNumberDialed = [phone lastNumberDialed];
// The phone might be brand new, so there might be no last-dialed-number...
if (lastNumberDialed) {
// Use the number, for example...
[myTextField setText:lastNumberDialed];
}
}
}
Now suppose you can send messages to nil (and always get nil back):
NSString *lastNumberDialed = [[[somePerson office] telephone] lastNumberDialed];
if (lastNumberDialed) {
[myTextField setText:lastNumberDialed];
}
As for why sending an unrecognized selector to an object raises an exception: I don't know for sure. I suspect that it's far more common for this to be a bug than to be harmless. In my code, I only want an unrecognized selector to be silently ignored when I need to send an optional protocol message (e.g. sending an optional message to a delegate). So I want the system to treat it as an error, and let me be explicit in the relatively rare case when I don't want it to be an error.
Note that you can tinker (to some extent) with the handling of unrecognized selectors in your own classes, in a few different ways. Take a look at the forwardingTargetForSelector:, forwardInvocation:, doesNotRecognizeSelector:, and resolveInstanceMethod: methods of NSObject.
From the good ol' documentation:
In Objective-C, it is valid to send a message to nil—it simply has no
effect at runtime.
As for the other problem of the unrecognized selector behavior, an old implementation file of NSObject (from the MySTEP library) shows that the culprit is the NSObject method -doesNotRecognizeSelector:, which looks a bit as follows:
- (void) doesNotRecognizeSelector:(SEL)aSelector
{
[NSException raise:NSInvalidArgumentException
format:#"NSObject %#[%# %#]: selector not recognized",
object_is_instance(self)?#"-":#"+",
NSStringFromClass([self class]),
NSStringFromSelector(aSelector)];
}
Which means that ObjC methods could feasibly be tinkered with so that they do not in fact have to raise an error. Which means the decision was entirely arbitrary, just like the decision to switch to "method-eating" messages to nil. A feat which can be done through method swizzling NSObject (wholly dangerous, as it will raise an EXC_BAD_ACCESS, or EXC_I386_BPT on mac, but at least it doesn't raise an exception)
void Swizzle(Class c, SEL orig, SEL new)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
}
-(void)example:(id)sender {
Swizzle([NSObject class], #selector(doesNotRecognizeSelector:), #selector(description));
[self performSelector:#selector(unrecog)];
}
The category:
#implementation NSObject (NoExceptionMessaging)
-(void)doesNotRecognizeSelector:(SEL)aSelector {
NSLog(#"I've got them good ol' no exception blues.");
}
#end
For everyone's amusement, due to the discussion CodaFi and I were having, here's a quickly-hacked-together way to eat normally unresponded-to messages and have them return nil:
#interface EaterOfBadMessages : NSObject
#end
#implementation EaterOfBadMessages
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature * sig = [super methodSignatureForSelector:aSelector];
if( !sig ){
sig = [NSMethodSignature signatureWithObjCTypes:"##:"];
}
return sig;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
id nilPtr = nil;
[anInvocation setReturnValue:&nilPtr];
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
EaterOfBadMessages * e = [[EaterOfBadMessages alloc] init];
// Of course, pre-ARC you could write [e chewOnThis]
NSLog(#"-[EaterOfBadMessages chewOnThis]: %#", [e performSelector:#selector(chewOnThis)]);
}
return 0;
}
Please don't use this in real life.

incompatible pointer type

I have this class:
#interface G2Matrix : NSObject
...
- (id) initWithArray:(float *)val;
...
#end
This line below give me a warning saying that the first argument to the method initWithArray has an incompatible pointer type:
float m[16];
...
G2Matrix* matrix = [[[G2Matrix alloc] initWithArray:m] autorelease];
If I change the method name to something like initWithArray1 the warning disappears. I know that some objects in foundation classes have a method with the same name, but I am deriving from NSObject, which doesn't have this method. What gives?
Additional info - I call the same initWithArray method from other init methods in the G2Matrix class, but I don't see the warning there.
At a guess, this is a type problem:
Inside the other init methods, you call [self initWithArray:...]. self is typed as a G2Matrix*. In this context the compiler can fully resolve which imp (C function pointer) will eventually handle the method call, and detect its signature (argument and return types) correctly.
Out in regular code, [G2Matrix alloc] returns an id. In this context the compiler can only tell the method selector, which will be bound to an imp at runtime. It has to guess which initWithArray: you mean, and as you can see from the warning it guesses wrong, since a foundation class has an initWithArray: method with a different signature. Your code does still work, the compiler just can't be certain.
Picking a unique name for the initMethod (initWithFloats: maybe?) is the recommended way to shut the warning up. Other ways are: break it into two lines; or cast the alloc return value to the right class:
G2Matrix *matrix = [G2Matrix alloc];
matrix = [[matrix initWithArray:pointerToFloats] autorelease];
// or
G2Matrix* matrix = [[(G2Matrix *)[G2Matrix alloc] initWithArray:m] autorelease];
Looks a little odd, but allows you to turn the treat-warnings-as-errors compiler flag back on.
#tathagata thats because initWithArray is method defined in NSArray class so you cannot use it unless you subclass NSArray class.
see the documentation on NSArray
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html
PS.
by use the method, i meant Override the existing method for your purpose which is not a good idea you can find the Subclassing Notes in the document.

Assigning to self in Objective-C

I'm from the C++ world so the notion of assigning this makes me shudder:
this = new Object; // Gah!
But in Objective-C there is a similar keyword, self, for which this is perfectly acceptable:
self = [super init]; // wait, what?
A lot of sample Objective-C code uses the above line in init routines. My questions:
1) Why does assignment to self make sense (answers like "because the language allows it" don't count)
2) What happens if I don't assign self in my init routine? Am I putting my instance in some kind of jeopardy?
3) When the following if statement fails, what does it mean and what should I do to recover from it:
- (id) init
{
self = [super init];
if (self)
{
self.my_foo = 42;
}
return self;
}
This is a topic that is frequently challenged by newcomers:
Wil Shipley: self = [stupid init];
Matt Gallagher: What does it mean when you assign [super init] to self?
Apple documentation: Implementing Initializers
Cocoa-Dev: self = [super init] debate
Basically, it stems from the idea that a superclass may have over-ridden the designated initializer to return a different object than the one returned from +alloc. If you didn't assign the return value of super's initializer into self, then you could potentially be dealing with a partially initialized object (because the object that super initialized isn't the same object that you're initializing).
On the whole, it's pretty rare for super to return something different, but it does happen in a couple of cases.
In Objective-C, initializers have the option of returning nil on failure or returning a completely different object than the one the initializer was called on (NSArray always does this, for example). If you don't capture the return value of init, the method might be executing in the context of a deallocated object.
Some people disagree about whether you should do the whole assign-to-self rigamarole if you don't expect to get something else back from the superclass initializer, but it's generally considered to be good defensive coding.
And yes, it looks weird.
It is true that init may return nil, if the initialization fails. But this is not the primary reason why you should assign to self when you implement your own initializers.
It has been mentioned before, but it is needed to stress even harder: the instance returned from an initializer may not be the same instance as the one you sent in, in fact it may not even be of the same class!
Some classes use this as a standard, for example all initializer to NSString and NSArray will always return a new instance of a different class. Initializers to UIColor will frequently return a different instance of a specialized class.
And you yourself can happely implement something like this if you want:
-(id)initWithName:(NSString*)name;
{
if ([name isEqualToString:#"Elvis"]) {
[self release];
self = [[TheKing alloc] init];
} else if (self = [super init]){
self.name = name;
}
return self;
}
This allows you to break out the implementation of some special case into a separate class, without requiring the clients of your API to care or even know about it.
All the other points here are valid, but it's important for you to understand as well that self is an implicit parameter to every Objective-C method (objc_msgSend() passes it) and can be written to, just like any other method parameter. (Writing to explicit parameters is generally frowned upon, unless they are out parameters.)
Typically, this is only done in the -init method, for the reasons others have stated. It only has any effect because self is returned from the method and used in the assignment id obj = [[NSObject alloc] init]; It also affects the implicit resolution of ivars, because, for example, if myVar is an ivar of my class, then accessing it in a method causes it to be implicitly resolved to self->myVar.
I'm still new to Objective C, but this post helped me in understanding this.
To sum it up, most init calls return the same object that self is already initialized to. If there is an error, then init will return nil. Also, some objects such as singletons or unique objects (like NSNumber 0) will return a different object than the one initialized (the singleton or a global 0 object). In these situations you need to have self reference that object. I'm by no means an expert in what is going on behind the scenes here, but it makes sense on the surface, to me.
If [super init] returns nil that means that you have been deallocated and your self parameter is now an invalid pointer. By blindly following the self = [super init] convention you will save you from potentially nasty bugs.
Consider the following non-typical initializer:
- (id)initWithParam:(id)param {
if (!param) {
// Bad param. Abort
self = [super init]; // What if [super init] returns nil?
[self release];
return nil;
}
else
{
// initialize with param.
...
}
}
Now what happens if my superclass decides to abort and return nil? I have been de-allocated and my self parameter is now invalid and [self release] will crash. By re-assigning self, I avoid that crash.