user2074102
user2074102

Reputation:

Release method not recognized at runtime (non Cocoa)

I'm a newbie to Objective-C but have extensive experience in C and C++. The first thing I have noticed is that there is a real void in basic tutorials out there as all assume you are developing for the iPhone or Mac and using Cocoa. I'm not using Cocoa or Gnustep. To the point:

As a simple example to get started I'm trying to wrap the C's File I/O functionality. My code starts as File.h

#include <objc/Object.h>
#include <stdio.h>
@interface File:Object
{
    FILE *pFile;
    char *path;
}

@property FILE *pFile;
@property char *path;

- (void)new;
- (void)OpenReadText:(const char*)var1;
- (void)release;

@end

And File.m

#include "File.h"

@implementation File

@synthesize pFile, path;

- (void)new
{
    self = [super init];
}
- (void)release
{
    fclose(pFile);
    [super release];
}

- (void)OpenReadText:(char*)var1
{
    path = var1;
    pFile = fopen(path,"r");
}

@end

Then main.m

#include <stdio.h>
#import <objc/Object.h>
#include "File.h"

int main(void) {

File *Fileobj = [File new];

[Fileobj OpenReadText:"File.h"];

[Fileobj release];


}

The compiler gives me a warning that my object "may not respond to '-release'". Then when running the program is results in a runtime error: "does not recognize release. This application has requested the Runtime to terminate" .. and so on.

I'm guessing I'm making a simple newbie error, but where? Or perhaps there is something missing? I'm hoping someone can point me in the right direction here. Thanks.

If this qst has been asked already then a reference would do too. I did try to find a reference but no luck.

FOLLOW UP:

changed release method to

- (void)release
{
    fclose(pFile);
    [super free];
}

and it appeared to work. Apparently free is recognized in object.h.

Upvotes: 2

Views: 247

Answers (3)

mttrb
mttrb

Reputation: 8345

As others have said it is unusual to use Objective-C without the Foundation frameworks. However, the Object class should implement release, retain etc. The Object class included (but not used) in Apple's Objective-C Runtime certainly contains these basic methods.

Assuming your Object class does contain these basic methods there are a couple of problems with your class as implemented.

First, you have created a new instance method which simply calls [super init]. The new method by convention is a class method which is shorthand for calling alloc and init to create and initialise an object. new is defined in Apple's Object class. It is implemented as:

+ (id)new
{
        id newObject = (*_alloc)((Class)self, 0);
        Class metaClass = self->isa;
        if (class_getVersion(metaClass) > 1)
            return [newObject init];
        else
            return newObject;
}

Note that this method is a class method, signified by the + instead of the -. GNUStep implements new as follows:

+ new
{
   return [[self alloc] init];
}

The idiomatic way to use new would be:

File *obj = [File new];

This is in fact what you have done, however, this is calling the class method new not your instance method new.

If you wanted to call your new method you'd have to call:

File *obj = [[File alloc] new];

but as others have stated you'd need to return your object. Removing your new method would have no effect on your implementation as it isn't currently being called.

Secondly, you have placed your call to fclose in your overriden release method. This is wrong, certainly in Apple's implementation of Object anyway, GNUstep appears to be different. release could get called multiple times on a single instance of an object. retain and release are used to increment/decrement the objects retain count. Only when the retain count reaches zero should the file handle be closed. Normally, within Foundation you'd place the call to fclose in a dealloc method. dealloc is Objective-C's destructor method. The dealloc should look something like:

- (void)dealloc
{
    fclose(pFile);
    [super dealloc];
}

However, dealloc doesn't appear to be implemented in either Apple's or GNUstep's Object class. There is, as you point out in your question a free method which seems to be a destructor.

It would appear that replacing the above dealloc method with an equivalent free method would work as a destructor, e.g.:

- (void)free
{
    fclose(pFile);
    [super free];
}

Apple's implementation of Object contains retain and release methods but the GNUstep implementation does not. Neither implementation contains a dealloc method.

The implementations of Object.m and NSObject.m for Apple and GNUstep can be found at the following locations:

Apple Object.m: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/Object.m

GNUstep Object.m: https://github.com/gnustep/gnustep-libobjc/blob/master/Object.m

Apple NSObject.mm: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/NSObject.mm

GNUstep NSObject.m: https://github.com/gnustep/gnustep-base/blob/master/Source/NSObject.m

Upvotes: 4

user2088639
user2088639

Reputation:

Is release defined on class Object? If it is not, then your call to

[super release];

will not work. (In cocoa, release is a member of NSObject; your Object class may or may not have it, and in fact the retain/release reference counting might not be there at all.)

You should confirm that your base class includes all methods called via super.

Upvotes: 2

Jasper Blues
Jasper Blues

Reputation: 28786

As @xlc0212 pointed out, the reference counting style of memory management is included in NSObject.

NSObject is a part of CoreFoundation library for Cocoa, CocoaTouch and GnuStep. I would say you need to link to CoreFoundation.

One book that I've read and focuses on pure Objective-C (not necessarily Cocoa) is "Programming in Objective-C 2.0" by Steven G Kochan.

Upvotes: 1

Related Questions