I am trying to learn objective c on windows. My program compiles with warnings
My code is
#include <objc/Object.h>
#interface Greeter:Object
{
/* This is left empty on purpose:
** Normally instance variables would be declared here,
** but these are not used in our example.
*/
}
- (void)greet;
#end
#include <stdio.h>
#implementation Greeter
- (void)greet
{
printf("Hello, World!\n");
}
#end
#include <stdlib.h>
int main(void)
{
id myGreeter;
myGreeter=[[Greeter alloc] init];
[myGreeter greet];
[myGreeter release];
return EXIT_SUCCESS;
}
I compile my program on GNUStep using the following command
gcc -o Greeter Greeter.m -I /GNUstep/System/Library/Headers -L /GNUstep/System/Libra
/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
I get the following warnings on compilation
: 'Greeter' may not respond to '+alloc' [enabled by default]
: (Messages without a matching method signature [enabled by default]
: will be assumed to return 'id' and accept [enabled by default]
: '...' as arguments.) [enabled by default]
: no '-init' method found [enabled by default]
: no '-release' method found [enabled by default]
And so when I run my executable the object does not get instantiated.
I am using gcc from MinGW where gcc version is 4.6.2
--UPDATE---
The program runs fine when I extend from NSObject instead of Object
--UPDATE 2 ----
My Object.h looks like
#include <objc/runtime.h>
#interface Object
{
Class isa;
}
#end
--UPDATE 3 ----
I have modified my code as follows. It compiles fine, but I am not sure if this is the right way to go about things
#interface Greeter
{
/* This is left empty on purpose:
** Normally instance variables would be declared here,
** but these are not used in our example.
*/
}
- (void)greet;
+ (id)alloc;
- (id)init;
- release;
#end
#include <stdio.h>
#implementation Greeter
- (void)greet
{
printf("Hello, World!\n");
}
+ (id)alloc
{
printf("Object created");
return self;
}
- (id)init
{
printf("Object instantiated");
return self;
}
- release {}
#end
#include <stdlib.h>
int main(void)
{
id myGreeter;
myGreeter=[[Greeter alloc] init];
[myGreeter greet];
[myGreeter release];
return EXIT_SUCCESS;
}
Unless you are studying the history of Objective-C, trying to learn the language based on the Object class is a complete waste of time. The Object class was last used commonly as a root class in pre-1994 NEXTSTEP.
If your goal is to learn pre-1994 Objective-C, then state that because, if so, the answers you have so far are entirely wrong. Even if the goal is to go with modern patterns, the answers are more along the lines of How do I recreate NSObject? than anything else. Note that if that is your goal.... well... go for it! Pre-1994 Objective-C was kinda like OOP macro-assembly and, through that, there was a ton of power through at the metal simplicity.
For example, you say that "I have modified my code as follows. It compiles fine, but I am not sure if this is the right way to go about things".
That code compiles, but -- no -- it doesn't work. Not at all. For starters, the +alloc method doesn't actually allocate anything. Nor does the Greeter class implement near enough functionality to act anything like an NSObject.
If your goal is to learn something akin to modern Objective-C and use Windows to do so, the best possible way would likely to be to install the GNUStep toolchain. With that, at least, you would be programming against an NSObject rooted set of APIs akin to modern Cocoa (and, to a lesser extent, iOS).
If your goal is to learn truly modern Objective-C, you'll want an environment that can run the latest versions of LLVM, at the very least. And, of course, if you want to write Objective-C based iOS or Mac OS X apps, you'll want a Mac running Lion.
From memory, the Object class does not implement retain counts, so it wouldn't have release, it'll have free or some other method. It should have +alloc and -init though. Since there's no “Objective-C standard”, you'll have to open up your objc/Object.h and see exactly what it offers.
Note that on GCC 4.6.2, objc/Object.h actually includes objc/deprecated/Object.h, meaning support for Object as a class may be fairly limited. If it doesn't include it, try including it yourself:
#import <objc/deprecated/Object.h>
Import Foundation.
#import <Foundation/Foundation.h>
Extend NSObject instead of Object.
#interface Greeter : NSObject
What I did was to install gcc-4.6 alongside the 4.7 that came with the linux system.
It seems to work, as it has a compatability layer for older code.
In my basic Makefile I specify
> CC=gcc-4.6
> LIBS=-lobjc -lpthread
>
> all: objc-test.m
> $(CC) -o objctest objc-test.m $(LIBS)
There is nothing "wrong" with using and older version of gcc.
The new 4.7 version has gutted
the objc system so it is not a stand-alone compilation suite. That sucks. I imagine there is some reason, possibly a political one, possibly just that it is difficult to make one compiler do it all for everyone. I have successfully made objc programs with gnustep in X86_64 Linux with gcc 4.7.3 after banging out failure for two days the old way.
It involves a bunch of setup:
setting up the environment variables with
source /usr/share/GNUstep/Makefiles/GNUstep.sh
and conforming to their build system.
A Basic GNUmakefile:
include $(GNUSTEP_MAKEFILES)/common.make
TOOL_NAME = test
test_OBJC_FILES = main.m
include $(GNUSTEP_MAKEFILES)/tool.make
for
main.m:
#import <Foundation/Foundation.h>
int
main (void)
{
NSLog (#"Executing");
return 0;
}
running
gs_make
builds the binary in a subdir obj.
It is actually quite frustrating to fight with the build system like that
and have to spend hours teasing out tidbitsfrom docs just to get basic functionality
from such a great compiler. I hope they fix it in coming iterations.
Have you tried with [Greeter new]; ? Open Object.h and take a look at the methods defined in the Object class...
EDIT:
To implement the alloc, retain and release you have to call the objc runtime.
So.. I think you have to write something like this:
#interface RootObject : Object
+ (id)alloc;
- (id)init;
- (id)retain;
- (void)release;
#end
#implementation RootObject
{
unsigned int retainCount;
}
+ (id)alloc
{
id myObj = class_createInstance([self class], 0);
/* FOR NEWBIES this works for GCC (default ubuntu 20.04 LTS)
id myObj = class_createInstance(self, 0);
*/
return myObj;
}
- (id)init
{
retainCount = 1;
return self;
}
- (id)retain
{
retainCount++;
return self;
}
- (void)release
{
retainCount--;
if (retainCount == 0) {
object_dispose(self);
}
}
#end
And then you can subclass RootObject.
Related
I am testing some simple Objective-C code on Windows (cygwin, gcc). This code already works in Xcode on Mac. I would like to convert my objects to not subclass NSObject (or anything else, lol). Is this possible, and how?
What I have so far:
// MyObject.h
#interface MyObject
- (void)myMethod:(int) param;
#end
and
// MyObject.m
#include "MyObject.h"
#interface MyObject()
{ // this line is a syntax error, why?
int _field;
}
#end
#implementation MyObject
- (id)init {
// what goes in here?
return self;
}
- (void)myMethod:(int) param {
_field = param;
}
#end
What happens when I try compiling it:
gcc -o test MyObject.m -lobjc
MyObject.m:4:1: error: expected identifier or ‘(’ before ‘{’ token
MyObject.m: In function ‘-[MyObject myMethod:]’:
MyObject.m:17:3: error: ‘_field’ undeclared (first use in this function)
EDIT My compiler is cygwin's gcc, also has cygwin gcc-objc package:
gcc --version
gcc (GCC) 4.7.3
I have tried looking for this online and in a couple of Objective-C tutorials, but every example of a class I have found inherits from NSObject. Is it really impossible to write Objective-C without Cocoa or some kind of Cocoa replacement that provides NSObject?
(Yes, I know about GNUstep. I would really rather avoid that if possible...)
EDIT This works:
// MyObject.h
#interface MyObject
#end
// MyObject.m
#include "MyObject.h"
#implementation MyObject
#end
Not very useful though...
It's possible to make classes without a base class. There are a couple of things going on. First, your compiler doesn't seem to like the "()" class extension syntax. Other compilers would be OK with it. If you remove those "()" on line four of MyObject.m then your compiler will complain that you've got two duplicate interfaces for the MyObject class. For the purpose of your test you should move that _field variable into the declaration of MyObject in the header file, like:
#interface MyObject {
int _field;
}
-(void)myMethod:(int)param;
#end
Then you can completely remove that extra #interface in the .m file. That should get you started at least.
It's possible, but note that NSObject implements the memory allocation API in objective-c, and if you don't implement NSObject's +alloc and -dealloc or equivalent on a root class, you'll still need to implement the same functionality for every class.
Although the overloading of # begins to tread on dangerous territory, I love the addition of the new Objective-C literals in Clang 3.1. Unfortunately the new literals are of limited use to me. Except for instances where code needs to interface with AppKit, I've mostly dropped the use of Foundation classes in favor of my own custom framework (for a variety of reasons; most of which is that I need direct control over the memory allocation patterns used by objects).
I could always use some runtime trickery to pass off the newly created object as my custom class (and is what I already have to do with string object literals, since only the non-Apple GCC runtime supports the -fconstantstring=class flag), but this is a hack at best and throws out all the benefits I gained by replacing the equivalent Foundation class to begin with.
Unlike string object literals, the new literals Clang implements are not actually constant classes (where the memory layout is hardcoded); instead the appropriate messages are sent to their respective classes to create and initialize a new object at runtime. The effect is no different than if you had created the object yourself. In theory it means that the classes used and the methods called by the new literals are not hardcoded. In practice I can't find any way to change them to point to my own custom classes and methods (I would in fact be happy just to point to a custom class; pointing a dummy method to an actual method at runtime isn't difficult).
When I first looked into this, I was really hoping to find a set of flags that could be used to do what I'm asking, but as I haven't found any, I'm hoping someone has a solution.
You can substitute class for some Objective-C literals with #compatibility_alias keyword trick.
Here's an example.
#compatibility_alias NSNumber AAA;
Of course, you should provide proper implementation for new class.
#import <Foundation/NSObject.h>
#interface AAA : NSObject
+ (id)numberWithInt:(int)num;
#end
#implementation AAA
+ (id)numberWithInt:(int)num
{
return #"AAAAA!!!"; // Abused type system just to check result.
}
#end
#compatibility_alias NSNumber AAA;
Now Clang will do the job for you. I confirmed this is working for number, array, dictionary literals. Unfortunately string literals seem to be emitted statically, so it won't work.
For more information about #compatibility_alias keyword, see here.
Note
Because #compatibility_alias keyword is a compiler directive which applies to current compilation unit, you need to separate compilation unit to avoid symbol duplication with NSObject class in Apple's Foundation Kit. Here's how I did it.
main.m
#import "test.h" // Comes before Foundation Kit.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool
{
NSLog(#"return of test = %#", test());
// insert code here...
NSLog(#"Hello, World!");
}
return 0;
}
test.h
id test();
test.m
#import "test.h"
#import <Foundation/NSObject.h>
#interface
AAA : NSObject
+ (id)numberWithInt:(int)v;
+ (id)arrayWithObjects:(id*)pobj count:(int)c;
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c;
#end
#implementation AAA
+ (id)numberWithInt:(int)v
{
return #"AAAAA as number!!!";
}
+ (id)arrayWithObjects:(id*)pobj count:(int)c
{
return #"AAAAA as array!!!";
}
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c
{
return #"AAAAA as dictionary!!!";
}
#end
#compatibility_alias NSDictionary AAA;
#compatibility_alias NSArray AAA;
#compatibility_alias NSNumber AAA;
id test()
{
// return #{};
// return #[];
return #55;
}
Result.
2013-03-23 08:54:42.793 return of test = AAAAA!!!
2013-03-23 08:54:42.796 Hello, World!
The comments have it all correct, but just to summarize:
No.
The meanings of Apple's #{}, #[], and #"" literals are hard-coded into Clang. You can see it here: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?view=markup It's all fairly modular, meaning that it wouldn't be hard for a Clang hacker to add her own literal syntax... but "modular" doesn't mean "accessible from the outside". Adding a new syntax or even redirecting the existing syntax to new classes would definitely require rebuilding Clang yourself.
Here's a blog post about adding NSURL literals to Clang by hacking on its internals: http://www.stuartcarnie.com/2012/06/llvm-clang-hacking-part-3.html (Thanks #Josh Caswell)
If you're willing to use Objective-C++ with C++11 extensions, you can has "user-defined literals", which allow you to write things like
NSURL *operator ""URL (const char *s) { return [NSURL URLWithString: #(s)]; }
int main() {
...
NSURL *myurl = "ftp://foo"URL;
...
}
This was mentioned in the comments on Mike Ash's blog. http://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.html But this doesn't look very Objective-C-ish (or very C++ish!), and it works only with an Objective-C++11 compiler, and in general please don't do this. :)
I'd like to write an Objective-C class without Cocoa or GNU's Object.h (for educational purposes). I dug around the net and it seems to me that quite a lot of stuff that one would expect to "come with the language", such as classes and message sending are actually defined in files written by third parties, such as objc-runtime.h.
Is there any documentation about what is really pure Objective-C and what is part of the runtime / frameworks? And what functionality do I have to implement to get a working environment without using any third-party code such as Object.h or objc-runtime.h (note again that this is for educational purposes, not for production code)?
Thanks for any insight!
Really, the only thing you must take care of yourself if you don't inherit from NSObject is object creation and destruction; methods otherwise behave the same way regardless of their parent class. Features like KVC and memory management are features of OpenStep/Cocoa, but not required as part of the language.
Here's a class from scratch:
#interface MyClass { // note the lack of a superclass here
#private Class isa;
}
+ (MyClass *)create;
- (void)destroy;
- (int)randomNumber;
#end
#implementation MyClass
+ (MyClass *)create {
return class_createInstance(self, 0);
}
- (void)destroy {
object_dispose(self);
}
- (int)randomNumber {
return rand();
}
#end
And here's how it could be used:
int main(int argc, char **argv) {
MyClass *foo = [MyClass create];
if (foo) {
printf("random! %i\n", [foo randomNumber]);
[foo destroy];
}
}
Edit: If you don't even want to use class_createInstance() and object_dispose(), you'll have to implement equivalents manually, as well as an equivalent of class_getInstanceSize() so you know how much memory an object occupies. But even if you manage that, don't think you've escaped the Objective-C runtime! Message dispatch is still entirely built on the C functions in the runtime, and Objective-C syntax is transformed into calls to those functions during compilation.
Matt Gallagher wrote a really cool post on writing a bare-bones Cocoa program. Since Objective-C is a superset of C, you can just do:
echo "int main(){return 0;}" | gcc -x objective-c -; ./a.out ; echo $?
Anyways, you probably would get a lot out of reading his post.
As far as avoiding the framework and creating your own base object goes, all you need to do is make sure that the first iVar is declared Class is_a and you could probably have a reasonable stab at replicating NSObject is by passing through to the runtime functions.
As far as avoiding the runtime library AND the framework goes, that's not really possible. Objective C (or at least, the bits that aren't just C) is a dynamic language. So pretty much everything it does that C doesn't do is handled by the runtime library.
It might be possible to build your own classes and objects using the 32bit runtime and the deprecated API, which doesn't abstract away the layout of classes, protocols, etc. to the extent that the modern runtime does (I've only really poked around with the modern runtime)
Perhaps you could create classes, add methods and allocate instances and by setting values in class_t structs and then using malloc() to allocate, although even then, you'd still be implicitly using the runtime function objc_msgSend every time you used the [obj selector] syntax -- unless you want to implement that as well, in which case you've just reimplemented the language yourself. The 'pure core' of the language you're looking for just is the runtime.
Here's an example of class, without using class_createInstance or object_dispose, or any other Objective-C Runtime (at least we don't call them directly).
#import <objc/objc.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
static Class __scratchClass = NULL;
#interface Scratch {
Class isa;
char *name;
}
+ (id) initialize;
+ (Scratch*) new:(const char*)strName;
- (void) sayHello;
- (void) destroy;
#end
#implementation Scratch
+ (id) initialize {
__scratchClass = self;
return self;
}
+ (Scratch*) new:(const char*) strName {
Scratch* pObj = (Scratch*)malloc(sizeof(Scratch));
if (!pObj) return NULL;
memset(pObj, 0, sizeof(Scratch));
pObj->isa = __scratchClass;
pObj->name = (char*)malloc(strlen(strName)+1);
strcpy(pObj->name, strName);
return pObj;
}
- (void) sayHello {
printf("Hello, World!\nThis is Scratch (%s)...\n", name);
}
- (void) destroy {
if (name) {
free(name);
name = NULL;
}
free(self);
}
#end
int main(int argc, char** argv) {
Scratch* ps = [Scratch new:argv[0]];
[ps sayHello];
[ps destroy];
return 0;
}
Compile the code with (assuming you save it as 'test1.m'):
gcc -o test1 test1.m -lobjc
I am currently moving from C to Objective-C and, to me, this code seems to be all find a dandy but Xcode thinks otherwise. I got this code sample from the internet and have been relentlessly trying to correct it and I've come to a deadend:
#include <objc/Object.h>
#interface Greeter:Object
{
/* This is left empty on purpose:
** Normally instance variables would be declared here,
** but these are not used in our example.
*/
}
- (void)greet;
#end
#include <stdio.h>
#implementation Greeter
- (void)greet
{
printf("Hello, World!\n");
}
#end
#include <stdlib.h>
int main(void)
{
id myGreeter;
myGreeter = [Greeter new];
[myGreeter greet];
[myGreeter release];
return 0;
}
The error seems to be on the myGreeter = [Greeter new]; line and the Xcode isolates the problem as something about Thread 1. Do I need to alloc/init anything?
Below is the console log:
[Switching to process 1833 thread 0x0]
2011-04-18 21:52:10.323 PROJ[1833:903] *** NSInvocation: warning: object 0x100001160 of class 'Greeter' does not implement methodSignatureForSelector: -- trouble ahead
2011-04-18 21:52:10.326 PROJ[1833:903] *** NSInvocation: warning: object 0x100001160 of class 'Greeter' does not implement doesNotRecognizeSelector: -- abort
sharedlibrary apply-load-rules all
Current language: auto; currently objective-c
(gdb)
Your class, Greeter, inherits from the Objective-C Object class. In Cocoa, the root class is (generally) NSObject, and you should inherit from that. This may fix your problem.
Greeter:Object should be Greeter:NSObject, "Object" is not an objective-c class.
Is this not just the Xcode debugger halting on the default breakpoint in "main" ? Simply click continue (or similar in the Run menu) and you should be golden.
Maybe I am wrong, but I always thought you allocated in Objective - C like this
id myGreeter;
myGreeter= [[myGreeter alloc] init];
Actually using new is, sort of, shorthand for the alloc/init, as you can read about here
HOWEVER, you're using objective-c outside of Cocoa it appears, because you're inheriting from Object and not NSObject and so on. So I think you should explicitly use myGreeter = [[myGreeter alloc] init];
Also since you say Xcode, you should be using Cocoa. Try:
#import <Cocoa/Cocoa.h>
And then also switch Object to NSObject
Your example uses the GNU runtime and thus is a bit deprecated. The compiler defaults to the NeXT runtime but can be set to use the GNU runtime with the compile option -fgnu-runtime
You should look into grabbing a good book about Objective-C like "Programming in Objective-C" by Stephen Kochan
http://www.amazon.com/Programming-Objective-C-Stephen-Kochan/dp/0672325861
I tried this code:
// main.m
#import <stdio.h>
#interface Test
+ (void)test;
#end
#implementation Test
+ (void)test
{
printf("test");
}
#end
int main()
{
[Test test];
return 0;
}
with LLVM/Clang without any framework, it doesn't compiled with this error:
Undefined symbols:
"_objc_msgSend", referenced from:
_main in main.o
ld: symbol(s) not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)
So I added libobjc.dylib. Code compiled, but threw this runtime exception:
objc[13896]: Test: Does not recognize selector forward::
Program received signal: “EXC_BAD_INSTRUCTION”.
#0 0x9932a4b4 in _objc_error
#1 0x9932a4ea in __objc_error
#2 0x993212b6 in _objc_msgForward
#3 0x99321299 in _objc_msgForward
#4 0x99321510 in _class_initialize
#5 0x99328972 in prepareForMethodLookup
#6 0x99329c17 in lookUpMethod
#7 0x99321367 in _class_lookupMethodAndLoadCache
#8 0x99320f13 in objc_msgSend
#9 0x00001ee5 in start
I realized some implementation required for root class, but I don't know what should I do next. What's required to make a new root class? And is there any specification for this?
I just came to this question because I had the same "academic" question. After working through it a bit, I have found that the other answers to this question aren't completely correct.
It is true that on the Apple Objective-C 2.0 runtime, you must implement certain methods in order for your code to work. There is actually only one method that you need to implement: the class method initialize.
#interface MyBase
+ (void)test;
#end
#implementation MyBase
+ (void)initialize {}
+ (void)test {
// whatever
}
#end
The runtime will automatically call initialize when you first use your class (as explained in Apple's documentation). Not implementing this method is the reason for the message forwarding error.
Compiling with clang test.m -Wall -lobjc (or gcc) will allow you to call the class method test without any issue. Making object allocation work is a different story. At the very least, you'll need an isa pointer on your base class if you're using instance variables. The runtime expects this to be there.
On the Apple runtime, the minimum specs are pretty easily explained: You have to implement every method in the NSObject protocol. See here. This is absolutely non-trivial. You might want to add a couple of additional functions like +alloc in order to be able to create an instance, etc. There are only two public root classes in all of Apple's frameworks: NSObject and NSProxy. In practice, there is absolutely no reason to create a root class. I'm not sure there is any documentation to this issue by Apple.
What you will do in practice is to inherit from NSObject or NSProxy and build on top of them. Your code will work if you do the following:
#interface Test : NSObject
+ (void)test;
#end
As Tilo pointed out, this is not the case on other runtimes like the GNU runtime.
In my system (GNUstep on linux + GCC) I had to replace the above alloc method with the following, to make the sample work. I think this is due to a newer obj-c runtime (documentation of the runtime here: Objective-C Runtime Reference from the Mac Developer Library.
+ alloc
{
return (id)class_createInstance(self, 0);
}
The above example compiles fine with gcc and GNU-runtime. In Objective-C normally any class can be a root class by simply not having a super class. If the Apple-runtime requires something different, then it's runtime specific.
Additionally there is something specific with root classes:
All instance methods are also class methods with the same implementation (if not explicitly implemented otherwise). The output of the following app:
#import <stdio.h>
#interface Test
+ alloc;
+ (void)test;
- (void)test;
- (void)otherTest;
#end
#implementation Test
+ alloc
{
return (id)class_create_instance(self);
}
+ (void)test
{
printf("class test\n");
}
- (void)test
{
printf("instance test\n");
}
- (void)otherTest
{
printf("otherTest\n");
}
#end
int main()
{
id t = [Test alloc];
[Test test];
[t test];
[Test otherTest];
[t otherTest];
return 0;
}
would be:
class test
instance test
otherTest
otherTest
The hardest part on creating a new root class is the +alloc and -dealloc but as seen in my example the runtime (in my case the GNU-runtime) can do this. But I don't know if the runtime allocation is good enough. I know that some foundations use an own allocation mechanism to hide the reference counter from the object structure. I don't know if Apple does this too and if their runtime already takes care of it.