discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Cocoa/GNUStep compatible build


From: pepijn de vos
Subject: Re: Cocoa/GNUStep compatible build
Date: Tue, 11 Sep 2012 05:56:34 -0700 (PDT)

Hi,

I dropped ARC for now. I found that with autorelease pools an getters and setters, refcounting is not that painful at all.

You hand written setter is tricky though. Most people seem to be using autorelease? I wonder what the actual synthesised methods look like.

What is the preferred way to generate an SHA1 hash? openssl is deprecated on Mac, but I don't think the Apple crypto package is available on GNUStep.

What happens when you have no autorelease pool? I was hoping it would crash, and tell me what happened, but I assume I'm just leaking memory now.

Pepijn


From: Ivan Vučica <ivucica@gmail.com>
To: pepijn de vos <pepijndevos@yahoo.com>
Cc: Steve Van Voorst <svanvoorst@hughes.net>; "Discuss-gnustep@gnu.org" <Discuss-gnustep@gnu.org>
Sent: Tuesday, September 4, 2012 2:12 PM
Subject: Re: Cocoa/GNUStep compatible build

Hi Pepijn,

I do have a blog, but I did not write any beginner things about GNUstep.

Try reading these tutorials from Nicola Pero:

Then, also take a look at this list of tutorials and articles:

Here are a few video tutorials on creating GUI apps, including on creating document-based apps, made by Sašo Kiselkov:

If you are a beginner, I would advise against using ARC. A lot of existing code does not use it, and if you want to support older compilers too, you won't be able to use it either. By all means, do switch to clang, but avoid using ARC, dot syntax and -- overall -- as many Objective-C 2.0 and later additions to the language. They're awesome once you understand what's happening "under the hood" and are very, VERY comfortable with language-specific "contracts". For example, you may have done manual refcounting before, but did you, in the past, use autorelease? Did you adhere to a strict naming convention, based on which you'd be able to conclude what the return value of the method would be?

When I speak of Objective-C 2.0 features, for example, there is no issue with you using @property and @synthesize... but spot the problem here:

- (void) setImportantText: (NSString *) importantText
{
  /* _importantText is the instance variable used for storage */ 
  [_importantText release];
  _importantText = [importantText retain];
}

Looks correct, right? Except it isn't. If you pass the same object that is currently set as the value of _importantText, and this object has refcount of zero, you'll end up releasing the object (and hence deallocating it), and then attempting to retain the same object. Congratulations! You crashed the app.

This is a hack that's close to the correct solution, since obviously the object will be released only later on:

- (void) setImportantText: (NSString *) importantText
{
  [_importantText autorelease];
  _importantText = [importantText retain];
}

Unfortunately, depending on how -setImportantText: is used, the person using your class may end up adding an enormous amount of objects to the autorelease pool, not expecting that they'll be released only later on.

How about this?

- (void) setImportantText: (NSString *) importantText
{
  if (importantText == _importantText)
    return; /* same pointer? definitely the same object, nothing to do */

  [importantText retain];
  [_importantText release];
  _importantText = importantText;
}

This way you ensured that the object definitely stays on "this side of the void, emptiness and nothingness". Then you let go of the old object, and you set the new value which is already retained.

I may be protecting the object too much (e.g. do I really have to pre-retain the object once I ensured it's not the same object? I'm not sure, but it doesn't hurt), or I may be protecting it too little (it does seem like the correct way to implement setters, but I may be wrong).

In any case, this is a very nice example of a thing you need to understand just in case you need to write a non-standard retaining property setter. (For example, it may be nicer to add behavior instead of using key-value observing.) If you understand the above, and are comfortable writing setters and getters manually, then by all means hurl yourself towards @property and @synthesize. If you understand retain/release and the strict naming conventions that ARC support in the compiler uses to insert calls to retain and release (or to optimize away the call and perhaps dig around the internal structures), and you don't consider it important that other developers who dislike ARC play around with your code, once again -- by all means, use ARC.

But definitely, definitely don't start with the new features. Don't think of Objective-C as a magical new language that does a billion things magically for you. (It does, but don't approach it like that, or else you'll end up disliking it as much as I ended up disliking C#; not because I understand it, but because I don't.)

Instead, think of Objective-C as of a small, tiny thing that gets you powerful dynamic object-oriented programming support in C. (Let's ignore the monstrosity that C++ is.) Instead of having to roll out your object-oriented layer in C, feeling like a victim of the NIH syndrome, or using GObject or something similar, you get a neat language that does very little, but opens many doors. When you use square brackets, consider that it's a call to objc_msgSend(). When you use "@interface ..." consider that a definition of a new struct {}. 

Think in terms of C with additions and with a strong culture of using conventions. Don't think in terms of C++, or in terms of a garbage collected language such as C#, Java or Python. Be happy about type-checking, but which gives just warnings when dealing with NSObject-derived objects. Don't be happy about ARC guessing where to call retain and release. Keep in mind the distinction between the language and the frameworks.

All these things will make sure you understand elementary concepts required to write code that's enjoyable to read and understand, that fits into the development culture, and that's as bug-free as possible.

On 4. 9. 2012., at 13:27, pepijn de vos <pepijndevos@yahoo.com> wrote:

Yes, I am new to Objective C, but I did manual refcounting in C before, so I understand you can't put vanilla C objects in NSDatastructures. My confusion was mainly with language features on different platforms and compilers.

Most tutorials are very Xcode and even iPhone focused. Not at all from the bottom up, but from the button up. There is very little in terms of google results on command-line tools and compilation.

So I finally figured out I need to add this to my makefile.

ADDITIONAL_FLAGS += -fobjc-arc
CC=clang

Now I will proceed to experiment with ARC and autorelease pools. I read you need to manage these yourself outside of Cocoa.

I would happily read a tutorial that is not about Xcode, rather than the docs.

Do you(or any old-fashioned ObjC coders here) have a blog? Even though I know some basics about refcounting, it was a nice read.

Pepijn


From: Ivan Vučica <ivucica@gmail.com>
To: pepijn de vos <pepijndevos@yahoo.com>
Cc: Steve Van Voorst <svanvoorst@hughes.net>; "Discuss-gnustep@gnu.org" <Discuss-gnustep@gnu.org>
Sent: Monday, September 3, 2012 11:15 PM
Subject: Re: Cocoa/GNUStep compatible build

So based on your surprise with regards to NSArrays, it sounds like you are completely new to Objective-C? You'll want to read some tutorials or books first, but this time I'll step in and give a non-GNUstep-specific piece of help (since it applies to Cocoa/Cocoa Touch as well).

First, Foundation framework is a reference counted environment to develop for. This means that according to a "contract" (that is, rules that Objective-C developers that use Foundation -- that's almost all of them -- decided to comply with) objects have a reference counter which is incremented and decremented based on some message sends ("method calls" in other languages).

These messages are -retain and -release. A utility method exists, -autorelease, which in concert with a utility class NSAutoreleasePool allows for adding an object to an autorelease pool, which is drained at regular intervals. Draining an autorelease pool is the same as sending all objects in the pool a -release message. In a GUI app, the intervals are not quite regular -- they are not created by some sort of a timer triggered by a hardware interrupt that would abort execution of your code and flush the autorelease pool. Rather, the place where the pool is drained is rather safe: it's done approximately in the place where the event loop resumes after your, app developer's, event-handling code has run.

-retain and -release are called when you want to claim "ownership" over an object ("hey, I might use it, don't let it disappear") or when you want to release your ownership ("that's fine, I'm done with it"). An internal counter is incremented or decremented. Objects that have their count decremented to zero are deallocated. Object's -dealloc method is called. Objects commonly call [super dealloc] to allow superclass to clean up the memory as well (typically by releasing all objects stored in instance variables). NSObject's dealloc actually frees the memory -- think of NSObject calling standard C function free().

Methods that, in their name, have "create", "alloc" and "new" (did I miss any?) will return an object with reference counter set to 1. This is not a language feature, but a "contract", a "convention" -- but one so far widespread you can almost treat it as a language feature. Class methods (the + ones) that have name of the class in its name typically return an object with 1 (-1) reference counter. By -1, I mean that the object has been added to the autorelease pool, and to ensure the object doesn't get deallocated, you'll want to increase the reference count to 2 (-1) using -retain, and consider that very soon, the reference counter will be just 1. If you don't do this, you'll get the hyper-cool feature that the object will be guaranteed to exist long enough to be returned from the function, but it'll get released very soon.


So what does this have to do with array?

See, the array actually wants to take ownership of an object. As stated above, that means an array is (by a contract!) bound to send -retain message  to each and every object added into it, no matter in what way. In your example below, you add the objects via the autoreleasing allocator+initializer class method, "+[NSArray arrayWithObjects:]".

If you pass numbers -- NSArray will happily treat each of them as pointers, and try to send -release method to an object stored at memory location, for example, 0x00000002.

As you might guess, there is no valid object stored at memory location 0x00000002.

So what can be done about the evil NSArray? Well, there's NSPointerArray. And under Apple's Cocoa environment, you could perhaps construct the NSArray using Core Foundation by specifying that no retain and release C function should be called for pointers added into CFArrayRef (which is toll-free-bridged into NSArray).

While first solution would be neat, it'd mean you can't mix other Objective-C objects (those based on NSObject) int the same array and ensure that they won't get deallocated prematurely. Second one, as far as I know, is available only for Apple platforms; I'm not sure how far GNUstep's CoreBase progressed.

So we reach the third solution: the one you posted below. You box non-Objective-C data types into NSNumber (for integers, floats, doubles, etc), NSDecimalNumber (for high-precision currency types), NSString (for strings), NSData (for unstructured byte streams) and NSValue (for all other C types; for example, structures). -valueForKey{Path}: and -setValue:forKey{Path}: make use of NSValue and NSNumber for non-Objective-C data types, and the original Objective-C data types for i-vars and KVO getters and setters that use, well, Objective-C data types.

So since NSValue and NSNumber are nice, clean and, dare I say it, sexy ways to pack various data types into something that can be retained and released just like Objective-C objects.

What you read about literals of NSArrays et al is a very new compiler thingy that I believe was introduced with Mountain Lion and Xcode 4.4's Clang. I have no idea how well and if it is supported in GNUstep, and don't even know the syntax; with something that new and limited to only one very new release of an OS, I couldn't really make use of it anyway. (See, I may be even wrong and it may be only a compiler trick, meaning this could be used on previous versions of the OS. I don't know though.)

In GNUstep community you'll find primarily "old-school Objective-C developers". Even dot-syntax for property access is looked down upon around here. My personal sentiment about, for example, ARC is negative, but that's primarily due to tastes and nothing else. I have no particular opinions about the dot syntax. I have no idea how well accepted the array and dictionary literals are or will be. What I'd suggest is that you first play with the basics.

Regarding the use of a compiler: Clang is where most new language features are first added. Why? Apple is the one adding the new features, and they currently favor Clang, due to their dislike of GCC's license. So if those features are to work, you almost certainly need to use Clang. To see which compiler you use (and all commands that gnustep-make orders GNU Make to run), type:
  make messages=yes


Let's wrap this up with a repeated call for you to first read up some more on Objective-C memory management and other basics. We'll be more than happy to answer your questions, but only if they don't require an extremely lengthy answer to a beginner's confusion like this one did. I made an exception, but you'll really want to get acquainted with the language first.

And do so with an older subset of the language, first; it'll be far easier to understand the inner workings of the language that way, and you'll be less confused by how properties work, how setters work, and what the dot syntax means.


Good luck!

On 3. 9. 2012., at 22:27, pepijn de vos <pepijndevos@yahoo.com> wrote:

Tanks for the help.

I created a brew formula for gnustep-make, and can compile a basic NSLog a... tool. https://github.com/mxcl/homebrew/pull/14645

However, I tried to do something "simple" like make a list of number and print those, or see if an NSArray has a hash.

It seems that you need to do something like [NSArray arrayWithObjects: [NSNumber numberWithInteger:1], [NSNumber numberWithInteger:1][NSNumber numberWithInteger:1], nil] or use classic C arrays.

I read that in recent versions of Objective C it is possible to create literals of NSArray, NSNumber and NSDictionary.

This does not work for me, except for NSStrings. Am I using the wrong compiler? I seem to be using gcc, can I tell it to use llvm?

Are these literals supported on Linux as well?

Pepijn


From: Ivan Vučica <ivucica@gmail.com>
To: Steve Van Voorst <svanvoorst@hughes.net>
Cc: pepijndevos@yahoo.com; Discuss-gnustep@gnu.org
Sent: Monday, September 3, 2012 12:07 AM
Subject: Re: Cocoa/GNUStep compatible build


On 2. 9. 2012., at 15:58, Steve Van Voorst <svanvoorst@hughes.net> wrote:

<<I want to write a command line app in Objective C that needs to run on Linux and Mac. I read I can use Foundation on Linux using GNUStep.  Do I need the whole of GNUStep, or can I just depend on Foundation?>>

In my experience, you need both <Foundation/Foundation.h> and <AppKit/AppKit.h>.  

Just to clear this up: if you are writing a command line tool, you definitely only need to include Foundation headers and link with Foundation. In fact, you don't even need to do that if you won't be using any classes from Foundation/gnustep-base. For example, you might write your own root class and use standard C input/output functions.

Regarding "app", we commonly call the command line stuff tools, not apps, in GNUstep; if it's a GUI program, then it's an app.

AppKit includes graphical components, such as windows, textfields, tabviews, et cetera. Unless you're writing a graphical app, you almost certainly don't need to include AppKit nor link with it. 












reply via email to

[Prev in Thread] Current Thread [Next in Thread]