2008/09/10
Fotonauts is now public !
Labels: fotonauts
2008/02/19
The cat...
2007/01/23
S3 Browser 1.0.6
Labels: s3
2007/01/10
Famous last words
"We've learned and struggled for a few years here figuring out how to make a decent phone, PC guys are not going to just figure this out. They're not going to just walk in."Palm CEO Ed Colligan, last month, about a hypothetical Apple iPhone
2006/12/31
S3 Browser: source repository and auto-updates
I made a few changes to S3 Browser this week. Not exactly new features or impressive bug fixes, but changes in how I'm coding and releasing S3 Browser.
First I moved my source repository to the objc-s3 project on Google Code Hosting, I was waiting for svnsync support, to be able to import my own subversion repository without losing history. So you can now checkout source code for S3 browser. This also means that I might not do source release for absolutely every minor version, but I always tag released versions in svn.
I was already using the issues tracker in Code Hosting. However I will probably not use the downloads area, the fact that it is not possible to remove a download is immediate show-stopper for me. If I ship a version with a very serious security problem (not likely considering what the application does with the keychain, but you never know), I want to be able to remove it as soon as possible. Ditto for a version that would have a major bug, deleting local files etc. "Tagging as obsolete" is not enough.
The only things I'm really missing from Trac are: a good SVN browser, the project Timeline, and automatic links in ticket numbers, revisions and changeset.
Another important change: I now use the Sparkle framework to manage application updating. I released a 1.0.2 with minor bugfixes and auto-update support. At launch, it should check the appcast feed and propose a 1.0.3 (one minor change, it's only to check update is working). Expect more frequent releases.
2006/12/17
Obj-C Runtime fun Redux
I got an email a few days ago asking for the code (never promise anything : you will have to deliver it eventually) so I dug in my disks to find a version of this code on a laptop harddrive that I planned to reformat...
Let me stress that this code is ultra-naïve, is a performance hog and is probably almost totally useless for anything serious. It was just a fun hack done in a few minutes, don't expect anything else. Oh, I'm might not work at all with the new Leopard Objective-2.0 runtime.
That being said, here is a quick walkthrough through the code. There's basically three parts in the hack:
- Use Objective-C reflection API to introspect class structure
- Navigate in an instance graph, processing class and instance variables name and values on the way, and keeping track visited objects.
- Dump DOT representation for the navigated instances.
Introspecting class structure might look a bit frightening: you don't have a full, clean, object-based reflection API in Objective-C similar to what you have in Java or C#, you will need to go back to runtime-level. The Apple Objective C Runtime documentation is a good reference. The interesting stuff is in #include <objc/objc-class.h>.
struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
/* ... */
struct objc_ivar_list *ivars;
};
typedef struct objc_class *Class;
struct objc_ivar {
char *ivar_name;
char *ivar_type;
int ivar_offset;
};
Cool. Everything we need to know about. Obtaining the struct objc_class from an Objective-C instance is straightforward: [myObject class].
Then we just have to iterate:
- (NSArray*)getFieldsForClass:(Class)klass
{
NSMutableArray* array = [NSMutableArray array];
int i;
Ivar ivar;
struct objc_ivar_list* ivarList = klass->ivars;
if (ivarList!= NULL && (ivarList->ivar_count>0)) {
for ( i = 0; i < ivarList->ivar_count; ++i ) {
rtIvar = (ivarList->ivar_list + i);
// Interesting stuff:
// ivar->ivar_type, ivar->ivar_name, ivar->ivar_offset
// Store this info in a OCVField object, add it to array
}
}
if (klass->super_class!=0)
[array addObjectsFromArray:[self getFieldsForClass:klass->super_class]];
return array;
}
The ivar_type is a string, a type encoding representing the ivar type. You might have encountered it with Foundation serialization. With the offset, we know where to peek from the instance pointer to get ivar value.
When you know the ivar name, you can also use the runtime function class_getInstanceVariable.
Then, browsing an instance graph is not that hard:
-(void)processFieldsForObject:(id)obj fields:(NSArray*)f toString:(NSMutableString*)s
{
OCVField* field;
NSEnumerator* e = [f objectEnumerator];
while (field = [e nextObject])
{
if (![field isPrimitive]) {
NSString* name = [field getName];
id ref = [field getValueForObject:obj];
if (ref==nil) {
// A link to a new "nil" node in the graphical reprensentation
// Why the special case ? we don't want a single nil node with
// hundred of links pointing to it.
}
else
{
// A link from obj to the 'ref' ivar value
[self appendGraphvizRepresentationFor:ref toString:s];
}
}
}
}
-(void)appendGraphvizRepresentationFor:(id)obj toString:(NSMutableString*)s
{
if (obj==nil)
obj = [NSNull null];
if ([visited containsObject:obj])
return;
[visited addObject:obj];
[obj appendDotRepresentationToString:s withContext:self];
if ([obj processFields])
[self processFieldsForObject:obj fields:[obj getFields] toString:s];
}
The only missing part is producing GraphViz Dot syntax. Objective-C categories are a nice way to implement that: we add methods to existing class, starting with NSObject to specify the Dot representation for an instance with the given type, and to authorize or not further ivar processing for the instance.
For example, for NSArray and NSDictionary, we'll have a custom representation, and for a NSString, we just want to output the "description" (e.g. the value) of the string instance:
@implementation NSString (DotRepresentation)
-(BOOL)processFields
{
return NO;
}
-(void)appendDotRepresentationToString:(NSMutableString*)s withContext:(OCVContext*)c
{
[s appendFormat:@"%@ [label=\"@\\\"%@\\\"\"];\n",[self dotName],[self description]];
}
@end
Et voilà: the dot file (for GraphViz, check out the great OS X version), or pdf rendering

Source code, BSD License. Please check the first post for additional notes.
Thanks Michael for the motivation !