Error : unrecognized selector sent to class - objective-c

I am a complete noob when it comes to Objective C (or even for OOP for that matter). Here is what I am trying to do
AInterface.m
#implementation AInterface
- (BOOL)getParam:(NSData **)a param1:(NSData**)param1 param2:(NSData**)param2
{
//Do a bunch of things
return bool;
}
#end
AInterface.h
#interface AInterface : NSObject
- (BOOL)getParam:(NSData **)a param1:(NSData**)param1 param2:(NSData**)param2;
+ (instancetype) inst;
#end
testMain.m()
int main()
{
Bool result = NO;
NSData *a = Nil;
NSData *b = Nil;
NSData *c = Nil;
result = [[AInterface inst] getParam:(NSData **)&a param1:(NSData**)&a param2:(NSData**)&b];
return result
}
When I run this though, I get an error saying failed:
caught "NSInvalidArgumentException", "+[AInterface inst]: unrecognized selector sent to class

Although you declared +inst method in #interface section your class does not have it implemented and that leads to runtime error. You need to add implementation to make it work, e.g.
#implementation AInterface
...
+ (instancetype)inst {
return [self new];
}

Your problem is that you don't have implementation of +inst in AInterface.m.
In your case inst would be something like:
[[AInterface alloc] init] but I'd just use [[AInterface alloc] init] instead of calling inst in the first place. Or [AInterface new], which stands for the same.
In general, the rest of your code is not idiomatic Objective-C.

Related

NSObject can not access property and method

I have a very strange problem, I have two classes the first one is a sub class of NSObject class it contains a method that add an object to its array. See the code below:
#import "portfolio.h"
#implementation portfolio
-(void) addStockObject:(stockHolding *)stock
{
[self.stocks addObject:stock ];
}
+(portfolio *) alloc
{
return [self.superclass alloc];
}
-(portfolio *) init
{
self.stocks=[[NSMutableArray alloc]init];
return self;
}
-(NSString *)getCurrentValue
{
stockHolding *stockInArray;
float currentValue=0.0;
for (NSInteger *i=0; i<[self.stocks count]; i++) {
stockInArray = [self.stocks objectAtIndex:i];
currentValue+=stockInArray.currentValue;
}
return [NSString stringWithFormat:#"Current Value: %f",currentValue];
}
#end
so when i call the method -(void) addStockObject:(stockHolding *)stock, i get the following error(during runtime):
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NSObject addStockObject:]: unrecognized selector
sent to instance 0x8b48d90'
The calling code is:
p=[[portfolio alloc]init];
[p addStockObject:s];
portfolio *p;
anyone can tell me what is wrong?
the other class has a property and it seems that it can not access it during compile time.
I'm really confused.
Thank you,
missa
First, never override +(portfolio *) alloc.
Second, init methods must call another init method and you must always check self for nil before setting ivars. Apple recommends against using properties to set ivars in init methods and init methods should always return instancetype in compilers that support it or id in those that don't.
-(instancetype) init
{
self = [super init];
if (self)
{
_stocks = [[NSMutableArray alloc] init];
}
return self;
}

Problems with subclasses inheriting class factory methods (Objective-C)

While I'm more than familiar with C#, I'm totally new at Objective C and iOS development. So I'm learning the language. What I don't understand is why the following code throws a compiler error (and yes, this is from the exercises at Programming with Objective C:
SNDPerson:
#interface SNDPerson : NSObject
#property NSString *first;
#property NSString *last;
+ (SNDPerson *)person;
#end
#implementation SNDPerson
+ (SNDPerson *)person
{
SNDPerson *retVal = [[self alloc] init];
retVal.first = #"Ari";
retVal.last = #"Roth";
return retVal;
}
#end
SNDShoutingPerson:
#import "SNDPerson.h"
#interface SNDShoutingPerson : SNDPerson
#end
#implementation SNDShoutingPerson
// Implementation is irrelevant here; all it does is override a method that prints a string
// in all caps. This works; I've tested it. However, if necessary I can provide more code.
// The goal here was for a concise repro.
#end
Main method:
- int main(int argc, const char * argv[])
{
SNDShoutingPerson *person = [[SNDShoutingPerson alloc] person]; // Error
...
}
The error is "No visible #interface for "SNDShoutingPerson" declares the selector "person".
Shouldn't this work? SNDShoutingPerson inherits from SNDPerson, so I would have assumed it got access to SNDPerson's class factory methods. Did I do something wrong here, or do I have to declare the method on SNDShoutingPerson's interface as well? The exercise text implies that what I did should Just Work.
Omit the +alloc when calling the class method:
SNDShoutingPerson *person = [SNDShoutingPerson person];
Briefly:
+ (id)foo denotes a class method. This takes the form:
[MONObject method];
- (id)foo denotes an instance method. This takes the form:
MONObject * object = ...; // << instance required
[object method];
Also, you can declare + (instancetype)person in this case, rather than + (SNDPerson *)person;.
change the line SNDShoutingPerson *person = [[SNDShoutingPerson alloc] person]; // Error
to
SNDShoutingPerson *person = [[SNDShoutingPerson alloc] init];
Cheers.
If you want to call class method:
SNDPerson person = [SNDPerson person];
person is a class method, but you're trying to call it with the incompletely constructed instance returned by alloc. Kill the alloc and just do [SNDShoutingPerson person].
This has nothing to do with subclasses, by the way. You would get the same error if you had written [[SNDPerson alloc] person].

Objective-C return instances of different classes at init

Is it possible at Objective C at init method to return an instance of different classes?
I'm having a Class called: MyCustomClass. I also have two other different classes called Class 1 and Class2. What I'm trying to implement is: When I call [[MyCustomClass alloc] initWithSomeParameters to create instance of Class1 or Class2 depending on some condition.
MyCustomClass.m:
#import "MyCustomClass.h"
#import "Class1.h"
#import "Class2.h"
-(id) initWithSomeParameters: (id) params{
id myClass;
if (someCondition){
myClass = [[Class1 alloc] initWithSomeParameters:(id) params];
[myClass setSomething:something];
}else{
myClass = [[Class2 alloc] initWithSomeParameters:(id) params];
[myClass setSomething:something];
}
return myClass;
}
...and later I call
id myCustomClass = [[MyCustomClass alloc] initWithSomeParameters:(id) params];
Is this a wrong approach? If so, what would be the correct one?
Several others have mentioned this, but the result of calling [[MyClass alloc] init] must always be nil or a kind of MyClass. It doesn't have to specifically be an instance of MyClass; one of its descendants is possible, as with NSArray or NSString. In code, this requirement would look like:
MyClass *a = [[MyClass alloc] init];
NSAssert((a==nil) || [a isKindOfClass:[MyClass class]], #"This must always hold true.");
I've never attempted to implement this, but it would probably have to look something like this:
- (id)initAsSubclass:(NSString *)sublcassName
{
Class c = NSClassFromString(subclassName);
self = [[c alloc] init];
if (self) {
// Do Custom Init Here
}
return self;
}
The keys would be:
DO NOT perform [super init].
Create a completely new object with +alloc.
Assign the newly created object to self.
If not using ARC, perform [self autorelease], before replacing the value. (If the object that is currently executing code becomes deallocated, it can cause issues. -autorelease will defer that until this section is complete.)
You should make some kind of controller, which initializes correct classes. You can also achieve same that using class methods.
ANd in genreal this given implementation is bad, because you alloc memory once [MyCustomClass alloc] and then in -(id)initWithSomeParameters:(id)params you are allocating memory again. So, even different address will be retruned, that isn't agains apple guidelines, some apple classes also have such behavior, but they do it because of optimizations. But here it is wrong.
Its not a good approach. Its better use some helper class or us factory pattern and provide parameters to method. Then depending on parameters create an object of class and return.
Its not good approach to create object of different class in init method of different class.
Edit:
if You want to show UIView or UIAlertView depending on iOS version do like this.
#interface AlertHelper : NSObject
+ (id)getAlert;
#end
///
#implementation AlertHelper
+(id)getAlert{
NSString *version = [[UIDevice currentDevice] systemVersion];
int ver = [version intValue];
if (ver < 7){
//For iOS 6
return something;
}
else{
//for ios 7
return something
}
}
#end
The way to do it is like this:
Create Base class like:
#import "Base.h"
#import "Class1.h"
#import "Class2.h"
#implementation Base
+ (id)classWithParams:(id)params
{
id retVal = nil;
if (condition_based_on_params_means_creating_class1)
{
retVal = [[Class1 alloc] initWithSomeParameters:params];
}
else
{
retVal = [[Class2 alloc] initWithSomeParameters:params]
}
return retVal;
}
#end
Class1 inherits from Base:
#interface Class1 : Base
{
}
- (id)initWithSomeParameters:(id)parameters;
#end
Class2 inherits from Base:
#interface Class2 : Base
{
}
- (id)initWithSomeParameters:(id)parameters;
#end
Ultimately you will have:
Base* a = [Base classWithParams:yourParams];

selector not sent by methodSignatureForSelector to forwardInvocation

I'm trying to change which method is called on an object for the sake of learning.
Here is my code.
#import <Foundation/Foundation.h>
#interface A : NSObject
-(void) say: (NSString*) s;
-(NSMethodSignature*) methodSignatureForSelector: (SEL) aSelector;
-(void) forwardInvocation: (NSInvocation*) invocation;
#end
#implementation A
-(void) say: (NSString*) s {
printf( "say \"%s\"", [s UTF8String] );
}
-(NSMethodSignature*) methodSignatureForSelector: (SEL) aSelector {
return [A instanceMethodSignatureForSelector: #selector(say:)];
}
-(void) forwardInvocation: (NSInvocation*) invocation {
// [invocation setSelector:#selector(say:)];
[invocation invokeWithTarget:self];
}
#end
int main(int args, char* argv[]){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
A* myObject = [[[A alloc] init] autorelease];
[myObject tryToSay:#"Hello strange method!"];
[pool release];
return 0;
}
I want to use -say: no matter which method is attempted used on objects of the class A.
The result is a Segfault.
It seems the invocation object sent to forwardInvocation still has #selector(tryToSay:) as its selector. Is it not supposed to get the same selector that was set in methodSignatureForSelector?
No, it's not. NSMethodSignature doesn't encode the selector. It encodes the signature of the method instead. This means things like the type and number of arguments. It's also not going to work correctly. If someone tries to invoke a method like -setInteger: which takes an NSUInteger, it will be passed to your method -say: which is expecting an NSString*. But it won't get an NSString*, it will get an NSUInteger, and any attempt to dereference that will crash (unless it's 0).

Class Composition Error?

I wonder if someone can explain where I am going wrong here, I am creating 2 objects (car & engine) where the car object contains a pointer to the engine object. I know I am missing the obvious or just making some silly mistake, but I can't quite put my finger on it.
NB: the code all works, except for the line that is comment ERROR.
// INTERFACE ------------------------------------------------------- **
#interface EngineClass : NSObject {
}
#end
#interface CarClass : NSObject {
EngineClass *engine;
}
- (void)setEngine:(EngineClass *)value;
#end
// IMPLEMENT ------------------------------------------------------- **
#implementation CarClass
- (void)setEngine:(EngineClass *)newEngine {
if (engine != newEngine) {
[engine release];
engine = [newEngine copy];
}
}
#end
#implementation EngineClass
#end
// MAIN ------------------------------------------------------------ **
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CarClass *newCar_001;
EngineClass *newEngine_001;
newCar_001 = [[CarClass alloc] init];
newEngine_001 = [[EngineClass alloc] init];
[newCar_001 setEngine: newEngine_001]; // ERROR
// Clean up
[newCar_001 release];
[newEngine_001 release];
[pool drain];
return 0;
}
// END ------------------------------------------------------------- **
The ERROR is ....
run
2009-09-22 13:41:05.483 cocoa_engine_TEST[8606:a0f]
2009-09-22 13:41:05.485 cocoa_engine_TEST[8606:a0f]
2009-09-22 13:41:05.485 cocoa_engine_TEST[8606:a0f] -[EngineClass copyWithZone:]: unrecognized selector sent to instance 0x10010c8d0
2009-09-22 13:41:05.486 cocoa_engine_TEST[8606:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[EngineClass copyWithZone:]: unrecognized selector sent to instance 0x10010c8d0'
cheers -gary-
From the docs for the copy method:
This is a convenience method for
classes that adopt the NSCopying
protocol. An exception is raised if
there is no implementation for
copyWithZone:.
Have you implemented copyWithZone?
And why copy engine when you could just retain?
- (id)copyWithZone:(NSZone *)zone {
EngineClass *engineCopy = [[EngineClass allocWithZone: zone] init];
// copy variables here, deep or shallow
return engineCopy;
}
It returns a retained object, as copy methods should.