Commentoir de Parmanoir

WAHa.06x36
2023 02 25

I don't think this is correct. X right, Y up and Z out of screen is right-handed. But CoreAnimation is not Y up, it is Y down. So it is actually left-handed, but with Z out of screen.

Nate
2014 01 31

Can you update this to work with Xcode 5? For some reason it won't let me build against the SDK.

Bronte Deng
2013 09 18

Thx,first.

I run your code, in my prj. Some error comes up for webview didnot load html file before invoking it.

So I add some code below:

In -[logData:file:lineNumber:]

if (![webView isWebViewLoaded]) {

   return;
}

In NSLogConsoleView - (BOOL)isWebViewLoaded;

tekka
2012 11 06

awesome,I'm learning your code

Rajesh
2012 07 09

I have used tail -f /NSLog.txt command in terminal, which made my XCode console doesn't show any log. I want to roll back and make my console work properly as earlier.

Can any one tell us command to roll back this.

Anthony Stevens
2012 02 09

You can also extend CALayer with a new class that implements this. Sadly your site doesn't allow me to post code so here's my best description:

Override CALayer.defaultActionForKey and return a nil for key = 'sublayers'.

Aaron Wallis
2011 06 13

Any idea if this kind of hack is accepted in the App Store?

Brian Palmer
2011 05 02

thanks, this took me all day to find. apple does not make things easy

Very nice list of uses. Thanks for posting.

Tony Arnold
2011 03 16

I used this approach in a recent release of my app, and I have to say — whilst it's quite clever, it blows out memory usage significantly due to the JS JIT compiler and other things being hosted in your app's memory space. If you don't have concerns about memory, this is a nice, simple approach — otherwise, I think you're better off finding something built on top of the simple POSIX regex tools.

Patrick Geiller
2011 01 07

@dvbfreaky : JSObjectMakeArray takes a C array as parameter. Allocate one and put your values in it :

JSValueRef* values = malloc(sizeof(JSValueRef)*itemCount);
array[0] = JSValueMake(...)
array[1] = ....
JSObjectRef jsArray = JSObjectMakeArray(ctx, itemCount, values, NULL);
free(values)
dvbfreaky
2011 01 07

Hi, please teach me, how to convert char* - string to JSArray Object.

char* -> JSStringRef . JSSTringRef->JSValueRef . JSValueRef ->JSValueMakeArray. Does not help. becase JSValueMakeArray need jsValue array as 3rd argument. Any help appreciated..

dvbfreaky007@gmail.com

Frank Hintsch
2010 10 29

Thanks for this wonderful peace of code. While testing I found that -init of NSLogConsole is called twice: 1st by NIB-Loader and 2nd by -sharedConsole.

Patrick Geiller
2010 07 20

You can. This post is an offshoot of exploring AppleScript, how it actually makes for (I think) simpler design even when not using it.

Jordy/Jediknil
2010 07 20

I haven't tried it, but can't you just bind to NSApp with a key path of @"delegate.myCustomKey"? No containers needed that way for longer key paths.

James Bedford
2010 06 10

This page and it's comments helped me out - thanks! :)

John
2010 05 27

Thanks. Would have been better if you could provide more explanation and complete examples.

Patrick Geiller
2010 05 12

A quick bench shows the get accessor 3% slower than valueForKey: and a set/get couple being 20 times slower.

Scott
2010 05 12

For the problem about Xcode complaining about non existant methods, just create a interface for a category on the class declaring the methods but don't implement category. Xcode will see the declarations

On a separate issue do you have any experience with performance. How much overhead does this create. Eg. Time to make 10000 accesses on this as opposed to just using objectForKey: and setObject:forKey:

I have done something similiar in creating acccessors at runtime by adding methods to a class that all route their implementation to a single c function that parses the selector to handle the actual data accesses. Being written in c I have sense is that it is only a minor overhead. I'll post this later as I have time. (btw. A good deal of credit for this technique goes to Jeff Lamarche.)

Actually, that behaviour is all over Mac OS X :-)

E.g. (after activating Desktop Exposé)

  • In Mail: ⇧⌘S
  • In Terminal: ⌘P
  • In Preview: ⌥⌘G

Patrick Geiller
2010 02 27

Ah, I didn't try the scaling yet. Good to know it's also useful there.

(& thanks for the bug report !)

Dan Wood
2010 02 27

Yeah, affine clamp is your friend! We use it in Sandvox for scaling images so that the scaled images have opaque edges - otherwise the fractional edge pixels will be translucent. Similar to the above transform and blurring issue.

(BTW, your blog commenting input system is not handling HTML entities properly... if one tries to enter an ampersand here, the comment will be rejected.)

Philip Taylor
2010 02 25

Thanks for this great introduction. There is precious little info on how to use the JavaScriptCore API.

Dan Grigsby
2010 01 05

Thanks for posting this. It's a nice to be able to see a complete gradient example put together in such a compact, straightforward way.

Patrick Geiller
2009 09 28

Yes, I'm following the Objective-J and JSTalk route.

Extending Javascript this way seems like a good idea.

Ryan
2009 09 25

This looks remarkably like the Objective-J code used for the Cappuccino framework. Are you doing something similar?

Patrick Geiller
2009 09 21

Thanks for the extra info and the __block bugfix !

KP
2009 09 21

A good list. You missed the concurrency options on the Foundation collections enumeration methods though, which some will find very convenient.

NSDictionary's enumeration methods provide an additional convenience; it passes both the key and the value for every entry in the dictionary. No more enumerating over the keys, then getting the values separately.

NSIndexSet also has a very useful enumeration method now. No more need to use the awkward -firstIndex and -indexGreaterThanIndex: approach.

There are also two NSString methods: enumerateSubstringsInRange:options:usingBlock:, which will let you enumerate lines, paragraphs, composed character sequences, words, or sentences, and the convenience method, enumerateLinesUsingBlock:.

Also, you have an error in #4. obj1-obj3 need to be __block variables. Otherwise, the block just captures the pointer values at the point where it is created.

Patrick Geiller
2009 08 14

You're welcome ! That's the sort of thing you can stumble upon when playing around with F-Script. It will let you explore all Cocoa classes and methods at runtime.

http://www.fscript.org/

Jens
2009 08 14

Great information, just what I've been looking for, for two days, night all over the net! You may want to add the following to one of your include-files...

@interface NSWindow (private)
- (void)setBottomCornerRounded:(BOOL)aFlag;
@end

...to avoid the compiler-warning and get a nice build.

Jens
2009 08 14

Patrick, you are a genious! :)

It's exactly what I've been looking for. -And I would probably not have found it without your help, as it seems it's a private API - it gives me a compiler warning that NSWindow may not respond to it, but I just checked that it respondsToSelector:@selector(setBottomCornerRounded) and I got a YES. =)

It's probably also far better than my 6 year old solution, thankyou a billion!

Patrick Geiller
2009 08 14

Jens, you're looking for NSWindow's setBottomCornerRounded.

http://parmanoir.com/NSWindow_goodies_:_bottomCornerRounded,_usesLightBottomGradient
Jens
2009 08 14

Great snippet!

I'm searching for a way to make the two bottom corners of a textured window have 'sharp' or 'square' corner like Safari, as I want a status bar down there. I once found out around 7 years ago, but I lost that snippet.

My solution was done when the window was initialized somehow, it didn't use more than 1 or 2 lines, but as I recall it, it didn't seem clear that it should/could be done this way.

I believe that I made a window in IB, then when loaded, I changed it from non-textured to textured, while I also changed some styling or something similar.

Do you by any chance know how to do this?

Chriss
2009 07 25

Very nice example ! Thanks a lot. Apple should provide that as sample code for CATextLayer.

Keith Duncan
2009 07 22

You can also use object_getClass(self) to return either the class or metaclass depending on wether self is an instance of a class or metaclass respectively.

Gunnar
2009 04 26

Neat stuff. I don't think I'd have found this on my own. I think it's ok for some button styles, but I wonder if there's a way to tweak it so it doesn't color the grey pixels around anti-aliased text. Thanks for sharing.

Patrick
2009 04 16

Nice fine :) Well done

Patrick Geiller
2009 03 15

You're welcome !

I just tried darkening the window, it quickly looks very dark. You might have to draw the title and the toolbar labels yourself.

William Dahlberg
2009 03 15

Cool tip! I was going to look into doing something like this for the app I'm working on to experiment with giving it a bit of a darker look. Not sure if it'll look good or just weird yet though, it's a fine line between giving an app a unique style and just messing with things that are already good. This technique seems easy enough to quickly find out though.

Thanks for sharing a way of doing it!

Patrick Geiller
2009 03 15

I guess it's possible. I wanted to draw over the existing frame, letting it handle drawing of buttons, toolbar, resize container, etc. Replacing the frame would mean I'd have to do it, and that's too much work ;)

Karsten
2009 03 15

can't you just replace the themeview with your own object? i mean, the NSWindow somehow sets this object, so i'm sure you can simply replace it. i guess you don't need to method swizzle NSThemeFrame, but instead create your subclass of NSThemeFrame and use that instead. I've just had a look. there's a _borderView instvar in NSWindow which keeps this theme frame so it could work if you change it, but i'm sure you'd need to do some housekeeping as well. like setting up the view in the window properly and such stuff...

Karsten

Patrick Geiller
2009 03 09

Ah indeed when I move the view on the side to be clipped by the window, redrawing is incorrect. Adding rect = [self bounds] before Scale down drawing rect fixes the issue. Thank you !

Qwerty Denzel
2009 03 09

The rect is the dirty rectangle that needs redrawing. When you resize the window and the view, the whole view needs updating.

However, a part of the view can also be chosen to redraw, through use of methods such as:

   - (void)setNeedsDisplayInRect:(NSRect)invalidRect

The invalidRect argument is then the rectangle used in the -drawRect: method. (Or if further rectangles are specified later, then a union of all those rectangles.)

By only invalidating what has changed, and then by drawing only what has been invalidated, your drawing becomes more efficient.

Picture where the user is working on some sort of elements in a view, such as selecting a range of text in a text view, or rolling their mouse over a list of buttons and having them highlight. Only a portion of the view is changing and needing to be redrawn.

If you launch the 'Quartz Debug' utility that shipped with your developer tools, you can enable options to flash, or highlight, the areas that are being updated on screen. You'll see that Apple are usually pretty efficient with the amount they redraw.

So coming back to the first point, since using rect is inappropriate, you should use -[NSView bounds] for finding the actual size of the view (in its drawing space).

Apply has a guide on efficient view drawing if you want more information.

Patrick Geiller
2009 03 08

I'm not noticing any difference between rect and [self bounds] ? What's it supposed to do ?

Qwerty Denzel
2009 03 08

A small niggle. Instead of using the rect argument, which is the region that needs updating, you should ask for the view's bounds.

NSRect bounds = [self bounds]; // Now use this for the full width and height.
Patrick Geiller
2008 12 19

So that explains the Ruby overexposure. I didn't expect it static languages to be that low. C+Java+C++ = 6% !

Jon Maddox
2008 12 19

Also, you'll find that those languages have a much more active open source community that have adopted modern collaboration tools like GitHub. Much more say than a mailing list oriented community like Cocoa.

It's a matter of who is using the site. The reason for the popularity of dynamic languages in Github is the people using it. The site was created in Ruby on Rails (though I believe Erlang is used in its backend as well) and I believe the Rails team is using Github as the repository for Rails. Plus, early on, the RoR world embraced Git as their SCM of choice, hence the popularity of Ruby, in particular. Because of this history, Github has become the darling of the startup oriented, web application development population, and so, languages that are most popular for developing web applications are going to be the most popular on Github.

At least, that's my theory anyway :-)

Ankur
2008 12 12

Or try man 3 freopen.

Patrick Geiller
2008 12 11

Thanks for the link ! As dup2 does redirect all stderr, it's really quite blunt.

I like that NSLog prints both in Xcode and in the console — opening Console. app is a quick and easy way to see if/where your app failed, so I'm all in favor of NSLog, debug or release :)

Jonathan Wight
2008 12 11

That doesn't strike me as the best way. All stderr output will go to the file in that case. That might not be optimal.

I used the following code to enable NSLog on the early iPhone betas (when NSLog was broken):

http://code.google.com/p/touchcode/source/browse/trunk/Experimental/Deprecated/TouchDebugging.m

(Not sure who I got the original code from - Jens maybe?)

It's my opinion that NSLog shouldn't exist in a non-debug app - you should be logging via a different mechanism (asl springs to mind). But these techniques are good as work arounds.

Krishen
2008 12 11

Thanks for the comparisons.. was wondering how/if they differed..

Patrick Geiller
2008 11 27

Thanks !

I've always felt the title bar was underused. All that space for a tiny bit of text … that's a shame :)

Matt Gallagher
2008 11 27

Nice diagram! Very pretty.

I don't know if I would ever put a help button there in my own program but it's fun to see people try things just because it can be done.

Dan Waylonis
2008 11 26

I ran into a similar problem -- thanks for sharing!

Pierre Bernard
2008 11 21

Tooting my own horn: try HoudahSpot.

"File name" "ends with" ".jscocoa"

Save as template

Patrick Geiller
2008 11 01

You do get a WebScriptObject, but you can call objectAtIndex on it.

Pieter
2008 10 31

Does passing arrays from JS to ObjC work for you? If I try it, I get a WebScriptObject instead of an NSArray (even though the docs say it's supposed to work).

Pascal
2008 10 29

Thank you, exactly what I was looking, for, too. :-)

Patrick Geiller
2008 10 27

Indeed. I'll add that.

Fishhead
2008 10 27

It would be interesting to see how they all look with syntax highlighting - that helps remove some of the visual noise in XML.

Patrick Geiller
2008 10 18

> Their answer was: this is by design, do not rely on app exiting from UIApplicationMain, the place to do cleanup is applicationWillTerminate: and nowhere else.

Hahaha ! What an answer ! :)

> I'm also not convinced creating and deallocating a global pool from an arbitrary point within your program flow really works. IMHO ugly things happen if you release a pool down in the stack while others are still on top.

Yes, this is ugly. I'll most likely create my JSCocoaController later in the code.

Regarding what happens, we can look at the gnustep code : http://svn.gna.org/viewcvs/gnustep/libs/base/trunk/Source/NSAutoreleasePool.m?rev=26258&view=markup — releasing one pool deallocates all its children. Maybe the Apple runtime works the same way. In any case, it doesn't crash and does kill all objects.

luz
2008 10 18

iPhone app templates already have that global autorelease pool in main.m your're suggesting. However, ironically it is not effective at all, as iPhone apps terminating do no exit from UIApplicationMain, but via an exit() somewhere within UIApplicationMain. I thought this was a bug a while ago reported it to Apple. Their answer was: this is by design, do not rely on app exiting from UIApplicationMain, the place to do cleanup is applicationWillTerminate: and nowhere else.

I'm also not convinced creating and deallocating a global pool from an arbitrary point within your program flow really works. IMHO ugly things happen if you release a pool down in the stack while others are still on top. And how do you know how many pools are open at the time you want to call your +deallocAutoreleasePool?

Patrick Geiller
2008 10 18

(I autorelease objects for convenience, eg in getProperty(), allocating a string to copy the property name from JS back to ObjC then autoreleasing it as I don't want to release it at each return of the function or use goto.)

> I would create an autorelease pool around the JSCocoaController initialization and call to evalJSFile:

evalJSFile will create ObjC classes that will be called back during NIB loading. Creating an autorelease pool just before calling, calling, then releasing the pool would remove the autorelease objects — that's what I want. This would work fine if I'm the only one autoreleasing, but the runtime might autorelease too, or the .js might be using functions like performSelector:withObject:afterDelay that would maybe leak if they happen before the runtime creates a new pool.

> Try putting an NSLog([NSString stringWithString:@"hi"]); after your call to NSApplicationMain() in a JSCocoa app.

You mean right in main.m ? Doesn't crash nor even log. Even a basic NSLog() fails to display anything — nothing shows up in the console or in console .app .

> I realize that's a real edge case, and that it may not really affect JSCocoa programs. But the bending of the autorelease pool conventions makes me cringe. At the very least I would leave a normal pool in place beneath your "remote-control" pool.

I don't think autorelease pools have any concept of 'beneath', just a stack getting pushed and popped by every pool alloc/dealloc. What I'm doing is popping that stack leaving it empty, then right after adding a new pool to it. That's why your NSLog doesn't crash as that pool is still in place. Which, thinking about it, might be BAD :) It should be released too after NSApplicationMain.

//

I'm well aware this is kludgy, but it works :) A cleaner solution would be to not use any JSCocoa objects in MainMenu .nib, and starting JSCocoa in the application delegate's awakeFromNib. I really like having an app delegate written in Javascript, but I might use a 'proxy' ObjC one and replace it with a JS one in awakeFromNib. I think I'll go down that route.

Jordy/Jediknil
2008 10 18

Well...I would create an autorelease pool around the JSCocoaController initialization and call to evalJSFile:. (I'm not familiar with JSCocoa, true, so maybe this isn't quite what you want.)

If you mean you need the objects to hang around until after the nib is loaded, well, I'm not sure you should be using autorelease then anyway; it breaks the semantics of "I'm done with this, if the caller wants it they better retain it". Classes in particular are supposed to stick around for the lifetime of the program.

I was going to suggest a safer variant which deallocated and reallocated the autorelease pool at the same time, but then I realized that both versions have a serious problem: when -awakeFromNib is called, AppKit has its own autorelease pool on the top of the autorelease stack. The pool you release is beneath that. If, by chance, the program pops its pool and does something, the "active" autorelease pool will have died already.

Try putting an NSLog([NSString stringWithString:@"hi"]); after your call to NSApplicationMain() in a JSCocoa app. If my suspicion is correct it'll crash or at the very least log an error...even if you put a third autorelease pool beneath the one from your method (e.g. [NSAutoreleasePool new] as the first line of your main function).

I realize that's a real edge case, and that it may not really affect JSCocoa programs. But the bending of the autorelease pool conventions makes me cringe. At the very least I would leave a normal pool in place beneath your "remote-control" pool.

Patrick Geiller
2008 10 17

I care about this because JSCocoa loads .js classes used by NIBs, and they must be created before NSApplicationMain loads the NIB. Using a top level autorelease pool will make some objects stick around until program end.

Popping the top pool kills objects when they're not needed anymore instead of killing them at program end. As JSCocoa logs instance count for debugging purposes, it allows me to check JSCocoa's GC logic.

The issue here is to have autoreleased objects used before NSApplicationMain, and discarded before program end. If you have a better solution I'll take it !

Jordy/Jediknil
2008 10 17

Oh, not to mention that AppKit creates and releases an autorelease pool around every run-loop cycle. It's not like random objects are sticking around anyway.

Jordy/Jediknil
2008 10 17

shudders This is awful...so many Cocoa classes depend on an autorelease pool being around. Autorelease pools stack anyway; if you really care about this, just create a new one in -awakeFromNib or -init. Except...then you might end up with your app delegate effectively holding onto its own reference. (You have that with your scheme as well.)

Why would you need such a thing? You shouldn't really be relying on -dealloc being executed anyway...that's what -applicationWillTerminate: is for.

Patrick Geiller
2008 10 16

@millenomi great stuff with the homepage YAML syntax :) It would be sheer hell in XML.

@Robert No problem :)

http://www.iro.umontreal.ca/~lapalme/ForestInsteadOfTheTrees/HTML/ch08s03.html has a XML -> JSON transformer.

Also, @sjamesu on Twitter pointed me to HAML  http://haml.hamptoncatlin.com/ — looks nice too.

Ideally I'd like to convert the result back to XML. Although I don't like XML, I really like XPath.

Heh - I was just going to suggest YAML - until I saw everybody else did already ;)

Now you've got me wondering if there are transformers between those markups. There's some help here: http://www.ibm.com/developerworks/forums/thread.jspa?messageID=21461

JSON is more or less a subset of YAML, so we're good at least one-way.

(Oh, and sorry for abusing your blog as part of my Google outboard brain - but I figured it was at least somewhat relevant to you, too)

millenomi
2008 10 16

What about YAML? www.yaml.org (the home page is valid YAML, if you want a sample.)

Patrick Geiller
2008 10 16

Wow, indeed YAML looks very nice. http://yaml.org/spec/1.2/#Preview

Dmitry Chestnykh
2008 10 16

YAML.

Patrick Geiller
2008 10 11

> Isn't in this case self already pointing to the right place after [super init]

No. An ObjC method is a C function taking two extra arguments : the instance and the selector. self does nothing more than point to that instance argument.

[super init] returning a new object (which does happen, see Mike Ash's article) means self has been destroyed — you need to account for that. The one valid object you have is the one returned by the parent init.

Gernot
2008 10 11

Correct me if I"m wrong: Always return from an -init whatever you have set self to. Even if you have to exchange the instance. Everything else is BAD style and WRONG.

Apples classes respect this (except for the obvious class clusters), and you should, too. And if that is the case it will work without the assignment.

Gernot
2008 10 11

But even if the superclass deallocates self and points it to another instance: Isn"t in this case self already pointing to the right place after [super init], thus making the assignment optional?

Patrick Geiller
2008 10 11

Hehe :) Didn't he concede after a guy wrote that program to test all ObjC classes ?

Dmitry Chestnykh
2008 10 11

Obligatory link to Wil Shipley's blog :) http://www.wilshipley.com/blog/2005/07/self-stupid-init.html

Rahul
2008 10 10

thanks for this javascript. This is certainly very good. cheers mate.

Tom Robinson
2008 10 10

Here's a command line wrapper I threw together: http://tlrobinson.net/blog/?p=55

Patrick Geiller
2008 10 09

(English below ! :) )

Oui, c'est possible. Pour l'instant, tout est ouvert et l'interpreteur passe par 2 endroits pour appeler des fonctions C ou Cocoa :

  • OSXObject_getPropertyCallback recupere les fonctions C classes ObjC, constantes : filtre propertyName pour interdire des fonctions C ou classes ObjC (interdire tout acces a NSView par ex)
  • jsCocoaObject_getProperty recupere les propriétés des instances : le nom d'un method, d'un propriété : filtre propertyName et inspecte callee pour interdire l'acces a des methodes ou propriétés d'une instance.

// English !

Right now everything is open : anyone can call anything : any C function, class method, …

  • To restrict access to only certain classes, C functions, structs, constants : filter propertyName in OSXObject_getPropertyCallback
  • To restrict access to only certain methods of certain classes, (eg allowing to call anything but alloc and init in NSView) filter propertyName with the help of callee (the instance being called) in OSXObject_getPropertyCallback
Mickaël Menu
2008 10 09

Ce projet à l'air vraiment prometteur, je vais le suivre avec attention. :) Est-ce que c'est possible d'isoler l'interpreteur de script afin d'éviter que les scripts puissent atteindre toute l'application hôte ? (Pour faire un système de plugins JavaScript, par exemple).

Patrick Geiller
2008 09 03

Stuff like open and write work just fine, but how do you use stuff like ioctl ? The man page is bare, the header file also, googling it yields differents results for Linux, BSD, … 

The main problem I have with file descriptors is finding documentation on the concept. I know that everything is a file, but using it is practice made me pull my hair. In NSLogConsole, I redirected stderr output to a pipe, this worked just fine when launched from XCode or the Terminal, but blocked when launching from Finder. Seems like because XCode and Terminal open a TTY before launching the app and redirecting stderr to a pipe works fine here, but blocks from Finder.

I tried opening dev/tty, tried to google some more info about pipes, async sockets, (and some exotic options to set with … ioctl), file descriptor concepts and came up with nothing working — I tried the UNIX way and failed, I tried the Cocoa way and succeeded pretty quickly.

Ankur
2008 09 03

> You like performance, I prefer convenience ;)

Very true.

> I've dabbled with open/read/write while writing NSLogConsole and quickly came back to ObjC

Keep in mind Objective-C is a superset of C.

> functions like open are unsearchable

Man pages contain example usage, possible pitfalls, existing bugs... Cmd-double click in Xcode to bring up the header file is also extremely useful. (I usually have more trouble with the framework references than with libc)

Patrick Geiller
2008 09 01

Not caring when the memory is released is exactly the point :)

The lifetime of malloc_autorelease memory is the same as autoreleased objects like [NSURL URLWithString:…] and serves the same purpose : use some data now and don't care when it's freed, thanks to dataWithBytesNoCopy that will do it for us.

Jon Hohle
2008 09 01

This has the odd side effect of the malloc'd memory being deallocated when the nearest autorelease pool as opposed to an explicit free. Since you're not returning the NSData* there is no way to retain the value for use later.

If you're method returned an NSData, you could still get at the element

NSData* tempData = malloc_autorelease(sizeof(element) * elementCount);
element* myTempData = (element*) [tempData bytes];
[tempData retain];
...
[tempData release];
Patrick Geiller
2008 08 30

You like performance, I prefer convenience ;)

I've dabbled with open/read/write while writing NSLogConsole and quickly came back to ObjC — functions like open are unsearchable, and I've had trouble finding documentation for stuff like ioctl. Even if createFileAtPath is slower, it's much easier to use.

Ankur
2008 08 30

Both createFileAtPath:contents:attributes: and writeToFile:atomically:encoding:error: ultimately call open anyway, but you get a lot of additional overhead. Better to do it yourself: man 2 open

Windows likes to use a BOM for UTF-8, but I don't we have that particular problem on OS X.

Patrick Geiller
2008 08 29

The file shows up as zero length in Terminal. According to Wikipedia, the BOM is used for UTF8 and UTF32 http://en.wikipedia.org/wiki/Byte%5FOrder%5FMark .

Apparently there is no way to mark the file with a particular encoding … maybe with metadata ?

Qwerty Denzel
2008 08 29

Not a Unicode expert, but I imagine the string @"" with utf-8 encoding would write with a byte order mark at the beginning.

Patrick Geiller
2008 08 28

Nothing ! I used writeToFile because it was the first thing I found in the help.

Scrod
2008 08 28

What's wrong with [[NSFileManager defaultManager] createFileAtPath:logPath contents:[NSData data] attributes:NULL];?

Patrick Geiller
2008 08 28

Alas I've never used Smalltalk !

As for numbers and nil … 

// Create an NSNumber
[@6.5 message]; 
// Create an NSNull
[@nil message]; 
// Bools too ?
[@YES message]; 

We could always lobby Apple for that :)

Karsten
2008 08 28

i think it looks more like Smalltalk than Javascript ;-) now if numbers and nil would also be objects, that'd be nice, but that's not gona happen in Obj-C :-)

Karsten

John McLaughlin
2008 08 18

Brilliant! This is really nicely done!

Patrick Geiller
2008 08 17

MIT license. Use freely !

Right now, launching from the Finder blocks on reading … works fine in XCode and Terminal. So don't use in production code :) Somehow stderr doesn't behave the same from Finder and from XCode. Any ideas ?

Karsten
2008 08 17

wow, great tool...thx!!

is there some sort of restriction to the source? or is it public domain?

Karsten

Patrick Geiller
2008 08 13

Thanks Rainer !

I did Google 'malloc autorelease' before writing that post, without finding anything relevant. I need to level up my Google-fu …

Patrick Geiller
2008 08 12

@Russell I've gone back reading NSData's doc and indeed both are equivalent. I didn't know dataWithBytesNoCopy:length: freed its pointer, its variant dataWithBytesNoCopy:length:freeWhenDone: apparently exists to create an NSData that will not free the pointer.

So dataWithBytesNoCopy:length: will work just as well !

Russell Finn
2008 08 12

Great tip, but I'm puzzled by one thing: isn't dataWithBytesNoCopy:p length:size freeWhenDone:YES equivalent to simply dataWithBytesNoCopy:p length:size? Or is there some subtle point I'm missing?

Keith Lazuka
2008 08 12

Whoops! You're right. Of course I go re-read your post after I submitted my comment. As long as there's an autorelease pool in scope, it will work. Sorry!

Keith Lazuka
2008 08 12

-[NSData dataWithBytesNoCopy:length:freeWhenDone] does not return void. It returns an NSData object that frees its buffer when it is dealloc'd. Since you throw away that NSData object, your implementation will never free the allocated buffer.

Dmitry Chestnykh
2008 08 12

Now, I like this solution, because it's readable :)

Patrick Geiller
2008 08 12

@ankur I'm doing that for convenience. I could shuffle around the code and free the data right in the function, but that's not high reward work as I'm not looking for speed in that particular case.

After considering goto, I think the best solution is to define a function named malloc_autorelease that will do just what its name implies - hiding the autoreleasing of the pointer and allowing to write code without thinking about memory freeing.

Qwerty Denzel
2008 08 12

@Bill I'm pretty sure doing free(ptr) if ptr = NULL is safe.

But you're right that you ideally should be checking if malloc returned NULL. Although it would likely mean you'd run out of memory, and the whole program would 'blow up' anyway!

Ankur
2008 08 12

Autorelease is expensive. Eliminate the BOOLs and do if(... || ...) rather than having two separate if statements. "Without PointerFreer" will be only one line longer than "With PointerFreer" and a heck of a lot faster.

Patrick Geiller
2008 08 11

@Ankur sometimes it's just not an option to delay malloc. That's doable, but that usually implies one call to count the elements and another to actually fill data — not delaying malloc makes that just one pass.

@Bill good point ! But as I didn't check for NULL after malloc(), I think it will blow up before reaching the free ;)

@Dmitry I'd missed the return success. Ok, I'll stop spurning goto now.

Dmitry Chestnykh
2008 08 11

But if you want to return YES or NO depending on your result, you still have to set a BOOL so that the goto can know what to return — or am I missing something?

See return success; in my example of goto.

Nice to see the Linux guys embrace goto !

I've just made a search and found 6695 goto's in the sources of XNU kernel. So Mac OS X guys also embrace goto ;) If you want an "approval" of a Cocoa programmer, here it is.

Bill
2008 08 11

In -setPointer:, you don't sanity check the argument for a NULL value. If you allow ptr to be assigned a NULL value, things will ultimately go boom when free(ptr) eventually gets invoked by -dealloc:

Ankur
2008 08 11

Why not just defer the malloc until after checking the conditions?

BOOL myFunction(...) {
    if(condition << anotherCondition) {
        myType* data = malloc(sizeof(myType)*elementCount);
        doSomeStuffWithData(data);
        free(data);
        return YES;
    } else {
        return NO;
    }
}
Patrick Geiller
2008 08 11

> Do you really need two classes to manage pointers ?

No, but I do need a better way to search the docs :)

Jonathan Wight
2008 08 11

NSData already does this. See:

  • (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)freeWhenDone;

Do you really need two classes to manage pointers?

Patrick Geiller
2008 08 10

Nice to see the Linux guys embrace goto ! But if you want to return YES or NO depending on your result, you still have to set a BOOL so that the goto can know what to return — or am I missing something ?

Yes I did mess up by calling it initWithPointer — I'll fix that. Thank you !

Dmitry Chestnykh
2008 08 10

BTW, by Cocoa conventions, you it's better to call your class method pointerFreererWithPointer or something like this, because initWith... are assumed to be instance methods, which return non-autoreleased objects. (Not that it's a restriction of some kind, just a convention).

Dmitry Chestnykh
2008 08 10

Using "goto" is really nice way to do cleanup, don't be afraid of it :) Arguments here.

BOOL myFunction(...)
{
    myType* data = malloc(sizeof(myType)*elementCount);

    // Check for something
    BOOL success = ...
    if (!success)
        goto cleaup;

    // Check for something else
    success = ...
    if (!success)
        goto cleanup;

    // Actual work !
    doSomeStuffWithData(data);

    // And free temp data
cleanup:
    free(data);
    return success;
}

Also, don't forget that with GC -dealloc is never called, so it's safer to have -finalize as well it you think you'll ever use your code in GC-required app ;)

Patrick Geiller
2008 07 25

Ah, yes. Thank you !

So … XCode warns about no rule to process file when the .js is in the wrong build phase. It uses CpResource to copy the .js if it's in the right build phase (Copy Bundle Resources).

Dmitry Chestnykh
2008 07 25

Yep. Build > Build Results > click on the tiny button with check mark.

Patrick Geiller
2008 07 19

Glad it's useful ! No link for your app yet ?

Patrick Geiller
2008 07 19

Nice, I didn't know you could set breakpoints on any symbol. Thank you !

millenomi
2008 07 19

It's in libSystem, so you don't (readily) have the code for it. You can use the Breakpoints window to create a symbol breakpoint for it by hand, though.

The clickable thingy is genius. In fact, TextMate does that with many kinds of error messages, for example PHP errors, and it's supremely useful there.

Anonymous
2008 07 18

For those who (like me) hadn't ever heard the word "doxa": it's the governing opinion, which is sublated through logos to episteme. Also a brand of watches. Wikipedia rules.

Patrick Geiller
2008 07 18

Indeed, but you have to repeat the condition :( which may be more complicated than if (node).

Qwerty Denzel
2008 07 18

You could also use a do while loop:

node = firstNode;
do {
    if (! someConditionOnNode )
        continue;
    compute !
} while ((node=node->next));

Note that this doesn't test for node being non-NULL initially. To do this you could probably just stick an if statement before like:

node = firstNode
if (node) do {
...
Dmitry Chestnykh
2008 07 17

Thanks! I used this in my app.

Patrick Geiller
2008 07 12

I've made the feed valid, I hope this fixes the duplicating.

If that doesn't do it, I'm out of options :)

Patrick Geiller
2008 07 12

If classes are objects, where are they defined ? I didn't find

@interface Class

in the headers. That's what I don't get about classes : they do behave like objects but Class is defined as a struct !?

player2
2008 07 12

...and I seem to have suffered from the same misreading. Sorry.

player2
2008 07 12

Classes are objects. They are of class Class. As mentioned before, you rarely need to actually know to what class an object belongs; just ask it -respondsToSelector: or -conformsToProtocol:. But if you really need to know if you're dealing with an object of a specific class Foo, just ask [obj isMemberOfClass:[Foo class]]. Putting two and two together, if you want to know if a specific object obj is actually a class, ask [obj isMemberOfClass:[Class class]].

Ah. In hindsight, I misread your article :) Thanks for clarifying

Patrick Geiller
2008 07 11

@Robert I'm writing a bridge from JavascriptCore to Cocoa and I need to know what kind of object the interpreter is giving me back. Agreed, that's extremely useless in everyday programming but that makes a nice blog post !

@Karsten You get my vote for pragmatic programming :)

@Dmitry Thanks for the hack ! So there is no official method. Frustrating since NSStringFromClass seems to be using the unofficial one …

Dmitry Chestnykh
2008 07 11

First:

BOOL isClass = ![object1 isMemberOfClass:[object1 class]];

Seems like class is not a member of itself ;)... However docs say:

"Class objects may be compiler-created objects but they still support
the concept  of membership. Thus, you can use this method to verify
that the receiver is a specific Class object."

Second, total hack:

BOOL isClass = (NSStringFromClass(object1) != nil);
Karsten
2008 07 10

why not implement a method: +isClass and -isClass or +isInstance and -isInstance in Object?

nothing to compare then, just return a YES and a NO in the right methods ;-)

Karsten

There is very rarely a need to know your class.

There are two places I know of where you (sort of) need to know a class.

1) You're working on backwards compatibility, some methods are only supported on newer versions of the OS. Use respondsToSelector: to figure out if your object is OK

2) You want to verify your object can behave a certain way. All you need to determine is if it conforms to a specific protocol - use conformsToProtocol:

That way, any implementation that satisfies those less stringent requirements will still work - you're not tied to your original choice of class.

Patrick Geiller
2008 07 09

I just checked with feedvalidator.org and my feed doesn't validate, I'll see how to fix that.

Jonathan Wight
2008 07 09

Hmm wonder if its just me then? :-)

Patrick Geiller
2008 07 09

Ouch ! How can that even happen ? I don't use NNW syncing, maybe the problem comes from here ? Have you tried unsubscribing then subscribing again ?

I didn't touch these CA posts after the template bug fix, Google reader does not mark them as new, NNW without syncing doesn't either, so I'm at loss why they keep getting popping up in your reader.

Jonathan Wight
2008 07 09

Just to show you how bad it is getting:

http://public.toxicsoftware.com/parmanoir.png

Maybe it is because I'm using newsgator syncing?

Patrick Geiller
2008 07 06

Several one in a day ?! Wow !

I don't know what to do, I sometimes launch NNW (3.1.5) to check the feed and I've never seen a read item not read.

:(

Jonathan Wight
2008 07 06

Seems to be all the CoreAnimation posts. Usually several in one day.

Patrick Geiller
2008 07 04

Yes, it's really a nice solution. It's too bad that Apple is using it to nag you into paying for more software instead of using it as help.

One nice example of this mechanism as help would be in Pages, for 'Instant Alpha' : its activation is not obvious — it only works on an image selection — and opening a window explaining that would be nice.

Alexander Repty
2008 07 04

I think this really is the solution to this problem. It is obvious at first look that the menu item is disabled and thus the user knows that it won't work right now. The "PRO" label also tells the user that they need to purchase the pro version of the application to enable the functionality, and if they need more info about it, they can just click the menu item.

Once more, Apple solved the problem before we even knew there was one.

Patrick Geiller
2008 07 02

I do get an error in this case. However, the original post is wrong — see my first comment, I copied the code and over cleaned it up to make it shorter.

Anonymous
2008 07 02

Patrick: Yes, that will crash. But the compiler should raise an error if you try to call the function with a different number of parameters, as your original code did. In fact, I tried to compile the following with gcc and got an error:

double (*fn)(void);
fn();
fn(2);
Patrick Geiller
2008 07 02

I tried adding the void, to no avail. The problem doesn't seem to be the first function definition, but that you can call any function pointer that hasn't been initialized :

double (*fn)(void);
fn();

will crash without any compile-time warning.

jmmv
2008 07 02

Should you have declared fn as 'double (*fn)(void) = sym;' (note the void in between the parenthesis), I expect the compiler would have detected an error in any kind of build; wouldn't it?

Patrick Geiller
2008 07 02

Argh … I messed up while copying and cleaning up the code for posting. I didn't assign to fn2 and then I called that undefined function pointer. It looked like this :

// No assignment
SomeStruct (*fn2)(float, float, float);
// Misassign to first pointer
fn = sym2;
// Call of undefined pointer
fn2(1, 2, 3);

GCC does catch the bug in the post, but not that one.

Moral2: You might want to crank up warnings to the highest level. In that case, you would have gotten a warning that you assigned to fn2 but never used the value.

(Not sure if gcc does that - spending too much time in VS.NET land these days)

Patrick Geiller
2008 06 29

Works best in Firefox 3. I just tested Webkit's nightly, it still locks up for up to 30 seconds in some cases. Firefox will just take 1-2 seconds to redisplay.

Patrick Geiller
2008 06 28

Arrrgh :) Which posts did it happen on ?

Jonathan Wight
2008 06 28

Still seems to be happening - but much less frequently. Oh well! :-)

Patrick Geiller
2008 06 23

Just tried NSUndoManager's valueForKey:@"_undoStack" and it works like a charm. Great tip, merci bien !

Florent Pillet
2008 06 23

An alternate (quick and easy) way of accessing private ivars is to use KVC, in particular -valueForKey: and -setValue:forKey: . Although some classes may trap this, most don't and it's a very useful technique that I use often (actually I used it too while in gdb console to inspect NSUndoManager stacks).

Patrick Geiller
2008 06 18

=begin … =end confused me too, and googling '=begin' to guess why they need to be positioned exactly at the start of the line or they won't work whas a pain.

That said, there are things I really love in Ruby, namely the return if (condition), the ability to omit parens in if/while/…. Too bad we can't cherry pick features from languages to make our own :)

kourge
2008 06 18

Ruby does have multiline comments. Multilines comments begin with =being and end with =end, although this confused me a lot when I first learned Ruby.

Also, coming from JavaScript to Ruby, I prefer the braces syntax over the do...end syntax when using blocks precisely because it's more syntactically similar to JavaScript.

Patrick Geiller
2008 06 06

Any idea why it's 'faked' and just one way ? It seems like more work than just making a 'value' property KVC compliant.

Jordy/Jediknil
2008 06 06

Yes there is, you use the accessors defined in NSControl (objectValue, doubleValue, floatValue, intValue, stringValue).

Binding to something requires a KVO-compliant key. Binding from something can evidently be faked (or at least renamed).

Patrick Geiller
2008 05 29

Browsing the logs I've seen someone from netblock-68-/-/-/.dslextreme.com trying to leave a comment here. I was doing some work on the admin side and your comment didn't make it through. Sorry ! Please repost if you come back.

Patrick Geiller
2008 05 29

Yes, we need to be careful about overlapping : I had an NSTableView slightly overlapping an NSBox, it repainted over the NSBox on scroll.

Note that in this case it worked well only when Core Animation was enabled.

//

I just got back to that overlapping NSBox, enabling Core Animation removes any repainting problems too. Nice :)

Jordy/Jediknil
2008 05 29

That is a very cool idea, but I'm torn because AppKit has never assured that overlapping views work. The Adding and Removing Views from a Hierarchy part of the View Programming Guide warns against it.

In practice, though, I've done this before too.

Patrick Geiller
2008 05 26

Ah yes, using NSPopUpButtonCell's attachPopUpWithFrame:inView: allows you to specify a rect. I hadn't seen that. Thank you !

player2
2008 05 26

I would think that the better way would be to include an NSPopupButtonCell that you don't draw but still pass mouse events to.

Patrick Geiller
2008 05 24

I hope everything's OK from here on.

As for CATiledLayer, I don't even understand its use. Don't expect sample code soon :)

Jonathan Wight
2008 05 24

That's great. I was wondering what was causing it. Keep up the good work with your CoreAnimation articles though.

I hope you tackle the secret gotches of CATiledLayer next. ;-)

Patrick Geiller
2008 05 24

That's because they are updated :) I use a template at the bottom of the Core Animation posts, when I add a new post I'll update the template with it and the old posts will get the new version of the template as well. I didn't realize this would mark the old posts as new. I'll look into it.

Jonathan Wight
2008 05 24

Hey there, your blog is awesome. I love the CoreAnimation postings especially. However, for some reason NNW keeps thinking your site is constantly updating the old blog posts and they keep appearing in my feed. I'm wondering if the problem is your end and if you'd take to look at fixing it?

Cheers.

Patrick Geiller
2008 05 22

Indeed, I forgot that. Fixed, thanks !

You'll need Mac OS X 10.5.2+.

Marc Driftmeyer
2008 05 22

Add a minimum operating system requirements description.

Patrick Geiller
2008 05 06

Just found this http://s-take.blogspot.com/2008/04/image-kit.html

… anybody read Japanese ?

Patrick Geiller
2008 05 04

Merci pour l'explication mathématique :)

vchahun
2008 05 04

Pour être précis, cette "règle de la main droite" signifie géométriquement qu'on choisit une base orthonormée directe de l'espace de dimension 3, alors qu'utiliser la main gauche conduirait au choix d'une base indirecte de l'espace ... ce qu'on fait moins souvent dans la pratique, pour des raisons de convention: sinon, il faudrait par exemple changer l'expression matricielle des rotations en dimension 3, etc. etc. Enfin, tant que c'est de la 2d augmentée, il faut juste savoir que l'axe des Z pointe vers le codeur et non pas l'écran !

Patrick Geiller
2008 05 01

Ah thanks, I didn't know the official name, just "* handed".

Anyway if you come from DirectX and code in Core Animation, hands are reversed. In a 3D engine, setting a badly signed Z value on layers would make them invisible. CA did draw them, inversely sorted.

Izzy
2008 05 01

Not to be a dick, but there is this thing called the "right hand rule" for 3-spaces.

Patrick Geiller
2008 04 28

Hi Karsten,

Ah yes, jrswizzle copies the parent implementation at the derived class level with class_addMethod. So it is simpler ! Thanks for the link.

Karsten
2008 04 28

wouldn't it be simpler to just use MethodSwizzling for that? Jonathan Rentzsch did a nice project to have a clean implementation of it. Michael Tsai bloged about it here: http://mjtsai.com/blog/2007/12/29/jrswizzle/

Karsten

Patrick Geiller
2008 04 25

No. Google Analytics is a piece of Javascript, I doubt it'd work in a RSS feed. And I only put the code in the website.

fpillet
2008 04 25

Does it count RSS readers too? 'cause when you have (like me) NetNewsWire configured to refresh feeds every hour, it increases the daily number of hits by a larger factor than just web visitors.

Patrick Geiller
2008 04 06

Woops ! Maybe I should have Bloom disabled by default. But it's so much prettier ... :)

Jonathan Wight
2008 04 06

Nice code!

Runs like a dog on Macbook (1st gen) until you turn bloom filter off. Then runs really smoothly.

Subscribed!

Patrick Geiller
2008 03 16

Answered on your blog. Thanks !

Scott Stevenson
2008 03 14

There's actually a "sphereContainer" sublayer that holds all of the floating orbs. I'm not sure what the exact effect was that you were going for, I changed this line:

mainLayer.sublayerTransform = transform;

To this:

sphereContainer.sublayerTransform = transform;

And it looks a lot better. I think Core Animation is actually doing the right thing. The NSView's backing layer had the sublayerTransform applied, so the sphereContainer layer was floating out in space.

Parmanoir