Uncaught exception NSInvalidArgumentException - objective-c

i am using tutorialspoint.com for compiling objective c code
#interface Foo{
#public
NSInteger x;
}
-(int) apple;
-(void)setAge:(NSInteger)number;
#end
#implementation Foo
-(int)apple{return 5;}
-(void)setAge:(NSInteger)number{
self->x=number+1;
NSLog(#"%d",self->x);
}
#end
int main (int argc, const char * argv[]){
NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
Foo *p = [[Foo alloc] init];NSInteger nine = 9;
[p setAge:nine];
[myPool drain];
return 0;
}
and i get this compilation error when i try to compile it:
main.m:41:3: warning: (Messages without a matching method signature
main.m:41:3: warning: will be assumed to return 'id' and accept
main.m:41:3: warning: '...' as arguments.)

Your class Foo has no base class (i. e. NSObject). Therefore +alloc and -init are not known for this class.
#interface Foo : NSObject {
…

Related

ObjectC-Why can't I get the properties correctly using the class_copyPropertyList function?

macOS 11.5.2
Xcode 13.2.1
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <iostream>
int main(int argc, const char * argv[]) {
#autoreleasepool {
Class clazz = NSClassFromString(#"NSString");
uint32_t count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (uint32_t i = 0; i < count; i++){
const char* name = property_getName(properties[i]);
std::cout << name << std::endl;
}
free(properties);
}
return 0;
}
I will take some snippets of the output:
hash
superclass
description
debugDescription
hash
superclass
description
debugDescription
vertexID
sha224
NS_isSourceOver
hash
superclass
description
debugDescription
...
From the output, we can find that properties such as hash, description, superclass, etc. will appear repeatedly several times, while some properties (such as UTF8String) do not appear in the result list.
How should I get the list of properties correctly?
I would appreciate it.
The reason you're not seeing UTF8String come up as a property is that it's not declared as a property in the main declaration of NSString, but rather in a category. On macOS 12.2.1/Xcode 13.2.1, the declaration of NSString boils down to this:
#interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
#property (readonly) NSUInteger length;
- (unichar)characterAtIndex:(NSUInteger)index;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
#end
All other properties and methods on NSString are declared in categories immediately afterwards:
#interface NSString (NSStringExtensionMethods)
#pragma mark *** Substrings ***
/* To avoid breaking up character sequences such as Emoji, you can do:
[str substringFromIndex:[str rangeOfComposedCharacterSequenceAtIndex:index].location]
[str substringToIndex:NSMaxRange([str rangeOfComposedCharacterSequenceAtIndex:index])]
[str substringWithRange:[str rangeOfComposedCharacterSequencesForRange:range]
*/
- (NSString *)substringFromIndex:(NSUInteger)from;
- (NSString *)substringToIndex:(NSUInteger)to;
// ...
#property (nullable, readonly) const char *UTF8String NS_RETURNS_INNER_POINTER; // Convenience to return null-terminated UTF8 representation
// ...
#end
When a property is declared in a category on a type like this, it doesn't get emitted as an actual Obj-C property because categories can only add methods to classes, and not instance variables. When a category declares a property on a type, it must be backed by a method and not a traditional property.
You can see this with a custom class, too — on my machine,
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface MyClass: NSObject
#property (nullable, readonly) const char *direct_UTF8String NS_RETURNS_INNER_POINTER;
#end
#interface MyClass (Extensions)
#property (nullable, readonly) const char *category_UTF8String NS_RETURNS_INNER_POINTER;
#end
#implementation MyClass
- (const char *)direct_UTF8String {
return "Hello, world!";
}
- (const char *)category_UTF8String {
return "Hi there!";
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
Class clazz = NSClassFromString(#"MyClass");
printf("%s properties:\n", class_getName(clazz));
uint32_t count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (uint32_t i = 0; i < count; i++){
printf("%s\n", property_getName(properties[i]));
}
free(properties);
puts("-----------------------------------------------");
printf("%s methods:\n", class_getName(clazz));
Method *methods = class_copyMethodList(clazz, &count);
for (uint32_t i = 0; i < count; i++) {
SEL name = method_getName(methods[i]);
printf("%s\n", sel_getName(name));
}
free(methods);
}
return 0;
}
outputs
MyClass properties:
direct_UTF8String
-----------------------------------------------
MyClass methods:
direct_UTF8String
category_UTF8String
If you remove the actual implementations of the *UTF8String methods from the class, the property remains declared, but the category method disappears (because it doesn't actually have a synthesized implementation because of how categories work):
MyClass properties:
direct_UTF8String
-----------------------------------------------
MyClass methods:
direct_UTF8String
As for how to adjust to this: it depends on what purpose you're trying to fetch properties for, and why you might need UTF8String specifically.
NSString declares in its interface it implements methods, but it does not actually implement them, that is why when you print at runtime a list of the its methods it does not print what you expect.
The methods are implemented by other private classes, and when you initialize a new instance of NSString, instead of getting an instance of NSString you get an instance of that private class that have the actual implementation.
You can see that by printing the class type of a string, the following prints NSCFString or NSTaggedPointerString, not NSString:
NSString* aString = [NSString stringWithFormat: #"something"];
NSLog(#"%#", [aString class]);
And this prints __NSCFConstantString:
NSLog(#"%#", [#"a constant string" class]);
This pattern is called a class cluster pattern.
If you modify to dump the methods of the NSCFString you will get a "redactedDescription", it seems you are prevented to query these classes.

What's happening when you synthesize a subclass' variable?

I have a superclass and a subclass. I can access the variable some_property (declared in the superclass) via self.some_property in the subclass.
However if I try to access the instance variable directly with _some_property, I'll get the error 'Use of undeclared identifier _some_property...'.
Using #synthesize some_property = _some_property silences this warning.
Whats going on when I re-synthesize the property?
You are creating another ivar named _some_property — and also overriding the getter method to return the value of this new ivar. The compiler gives you an error about this if the base class's #implementation (i.e. the implicit declaration of its _some_property ivar) is visible at the site of the #synthesize in the subclass.
(By the way, don't do this!)
You can demonstrate to yourself by inspecting the Obj-C runtime:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface Base : NSObject
#property id foo;
#end
#interface Derived : Base
#end
#implementation Derived
#synthesize foo=_foo; // the compiler doesn't know about Base's _foo yet, so this is OK...
- (instancetype)init {
if ((self = [super init])) {
_foo = #"I'm derived";
}
return self;
}
#end
#implementation Base // after Derived to avoid the error
- (instancetype)init {
if ((self = [super init])) {
_foo = #"I'm base";
}
return self;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
Derived *obj = [Derived new];
NSLog(#"getter returns %#", obj.foo);
unsigned int count = 0;
// Examine Base ivars
NSLog(#"Base ivars:");
Ivar *ivars = class_copyIvarList([Base class], &count);
for (unsigned int i = 0; i < count; i++) {
NSLog(#" %s = %#", ivar_getName(ivars[i]), object_getIvar(obj, ivars[i]));
}
// Examine Derived ivars
NSLog(#"Derived ivars:");
ivars = class_copyIvarList([Derived class], &count);
for (unsigned int i = 0; i < count; i++) {
NSLog(#" %s = %#", ivar_getName(ivars[i]), object_getIvar(obj, ivars[i]));
}
}
return 0;
}
Output:
getter returns I'm derived
Base ivars:
_foo = I'm base
Derived ivars:
_foo = I'm derived

Potential problems in objective-c code

Here is a small piece of code. Posted by Russian company Yandex as a part of their interview. What are potential problems here? It looks very simple, should be hidden problems I can not see.
First header
//Foo.h
#import <Cocoa/Cocoa.h>
#interface Foo : NSObject
{
NSString* str;
static int i = 0;
}
- (NSString*) str;
#end
Another file
//Foo.m
#import "Foo.h"
#implementation
- (id) init
{
return [self initWithStr:"number:" someInt:6];
}
- (id) initWithStr:(NSString*)theStr someInt:(int)value
{
self = [super init];
str = [NSString stringWithFormat:#"%#%d", theStr, value];
return self;
}
- (NSString*) str
{
return str;
}
- (void) setStr:(NSString*)theStr
{
str = theStr;
}
#end
And the last file
//main.m
#import <Cocoa/Cocoa.h>
#import "Foo.h"
int main(int argc, char *argv[])
{
Foo objA;
NSLog([objA str]);
[objA setStr:#"hello world!"];
NSLog([objA str]);
Foo* objB = [[Foo alloc] init];
Foo* objC = [[Foo alloc] initWithStr:#"My magic number:" value:265];
objB = objC;
NSLog([objB str]);
[objA release];
[objB release];
[objC release];
return 0;
}
In another file:
#implementation
implementation of what? must specify.
In the last file:
Foo objA;
NSLog([objA str]);
[objA setStr:#"hello world!"];
NSLog([objA str]);
This will crash, local variable Foo objA is not initialized, it would be fine it was set to nil, since messages to nil are ok in objective c but it is not.
Here:
[objA setStr:#"hello world!"];
That method will give a compile warning since that method is not declared in the interface, but it will still call the method.
Here:
- (id) init
{
return [self initWithStr:"number:" someInt:6];
}
Missing # for the string #"number:"
Here:
objB = objC;
You just leaked objB, since there is now no valid reference to release the previous allocation.
[objA release];
This was never allocated!
[objB release];
[objC release];
The second one will crash since they both refer to the same object, and the retain count is only 1.
The first file also has some potential issues such as declaring a method that appears to be a getter without declaring a property for the ivar, same with the setter, would be better to just declare a property.
#interface Foo : NSObject
{
NSString* str;
static int i = 0;
}
You cann't define static int i = 0; here. Type name does not allow storage class to be specified Foo.h
Also, the setter needs to release the previous string and retain the new one.
- (void) setStr:(NSString*)theStr
{
if(str) {
[str release];
}
str = [theStr retain];
}

gcc compile errors in an basic example objc program

Hey all, I'm new to programming and going through an objective-c book to learn the language and programing fundamentals. I've looked through the code repeatedly, went back to the book's example, and attempted to understand the gcc comple errors. Here's my code:
#import <stdio.h>
#import <objc/Object.h>
#interface Point: Object
{
int xaxis;
int yaxis;
}
-(void) print;
-(void) setx: (int)x;
-(void) sety: (int)y;
#end
#implementation Point;
-(void) print
{
printf("(%i,%i)", xaxis, yaxis);
}
-(void) setx: (int) x
{
xaxis = x;
}
-(void) sety: (int) y
{
yaxis = y;
}
#end
int main (int argc, char *argv[])
{
Point *myPoint;
myPoint = [Point alloc];
myPoint = [myPoint init];
[myPoint setx: 4];
[myPoint sety: 5];
printf("The coordinates are: ");
[myPoint print];
printf("\n");
[myPoint free];
return 0;
}
Then the compile errors from gcc look like this:
urban:Desktop alex$ gcc point.m -o point -l objc
point.m: In function ‘main’:
point.m:38: warning: ‘Point’ may not respond to ‘+alloc’
point.m:38: warning: (Messages without a matching method signature
point.m:38: warning: will be assumed to return ‘id’ and accept
point.m:38: warning: ‘...’ as arguments.)
point.m:40: error: ‘mypoint’ undeclared (first use in this function)
point.m:40: error: (Each undeclared identifier is reported only once
point.m:40: error: for each function it appears in.)
point.m:49: warning: ‘Point’ may not respond to ‘-free’
Where am I going wrong?
btw I'm going through "Programming in Objective-C" by Stephen Kochan if you wanted to know.
First the base class should be NSObject, not Object
the normal way to do the initialization is to write the alloc and init in the same statement. You would typically have an -(id)init; method in your class:
-(id)init
{
if ( ( self = [super init] ) )
{
; // additional initialization goes here
}
return self;
}
and
int main (int argc, char *argv[])
{
Point *myPoint = [[Point alloc] init];
Properties are better used, then you get the setter and getter automatically generated for you
instead of
#interface Point: Object
{
int xaxis;
int yaxis;
}
write
#interface Point : NSObject
{
}
#property int xaxis;
#property int yaxis;
then when you assign you can either write
[myPoint setXaxis:4]
or
myPoint.xaxis = 4;
when you release the object write release, not free
[myPoint release];
hth
You have warnings and an error. The warnings seem to suggest that Object, which you are subclassing, doesn't implement alloc, init or free. Normally, on an Apple platform, you'd subclass NSObject, which does implement these, but without knowing which platform you're on, it's not possible to advise the correct option.
Secondly, you had a typo, but that now seems to be corrected. This
point.m:40: error: ‘mypoint’ undeclared (first use in this function)
suggests that you had mypoint in your code, rather than myPoint.
You forgot to include the header Foundation.h:
#import <Foundation/Foundation.h>

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.