views:

158

answers:

4

Hi,

I know that there are functions in the objective-c runtime that allow you to create objects directly, such as class_createInstance. What I would like to know is if anything actually uses these functions other than the root classes' (NSObject) alloc method. I think things like KVC bindings might, but those aren't present on the iPhone OS (to my knowledge, correct me if I'm wrong), so is there anything that would do this?

In case you're wondering/it matters, I'm looking to allocate the size of an instance in a way that circumvents the objc runtime by declaring no ivars on a class, but overriding the +alloc method and calling class_createInstance(self, numberofbytesofmyivars).

Thanks

EDIT I think I need to be more specific. I am adding classes to the runtime at runtime, and possibly unload and reload an altered version of the same class. I've worked around most of the issues so far, due to things like class_addMethod, but there's no equivalent for ivars after the class has been registered. The two solutions I can think of are having no actual ivars as far as the runtime is concerned, but overriding alloc to make sure I have enough room for them through extraBytes, or alternatively declaring an ivar which is a pointer to all of my actual ivars, which I can then obviously do whatever I want with. I would prefer to use the former strategy but there are a number of things that can go wrong, like if something allocates an instance of my object without going through my overloaded alloc method. Does anyone know of one of these things?

A: 

I'm not sure why you'd want to do what you're suggesting--I don't see any reason you couldn't do it, but according to this post, there's usually no reason to use class_createInstance directly (I don't know of anything that uses it specifically). class_createInstance also doesn't take into account memory zones or other possible optimizations used by alloc. If you're just trying to hide your ivars, there are better ways.

EDIT: I think you're looking for the class_addIvar function, which (as the name suggests) dynamically adds an ivar to a class. It only works with the new runtime, so it won't work on the simulator, but it will work on the iPhone.

EDIT 2: Just to be totally clear (in case it wasn't already), you can definitely rely on allocWithZone always being called. Fundamental Cocoa classes, such as NSString and NSArray, override allocWithZone. class_createInstance is almost never used except at the runtime level, so you don't have to worry about any parts of Cocoa using it on your classes. So the answer to the original question is "no" (or more specifically, objects are sometimes created without alloc, but not without allocWithZone, at least as far as I know).

eman
If you read the docs a little closer you'll see that adding ivars can only happen between when the class is allocated and when it is registered. In the question I specify that I need to be able to load/unload varients of the same class, such as with different ivars. There is no way to unload a class from the runtime, or replace it.
Jared P
Sorry, I didn't see that. To answer your original question (which I think I understand now), it's safe to assume that `allocWithZone` will always be called--a lot of fundamental Cocoa classes (such as NSArray and NSString) are implemented as class clusters, and override `allocWithZone`. Also, in case it helps, you generally call `NSAllocateObject` instead of `class_createInstance` (I'm not actually sure of the exact difference).
eman
NSAllocateObject calls class_createInstance. All the NS* functions just wrap the equivalent Objective-C runtime functions.
rpetrich
A: 

Well there is nothing technically to stop you from overriding alloc. Just create a method in your class called +alloc. I just can't imagine any reason why you would need to.

JeremyP
+1  A: 

I'm not sure if you're trying to change the behavior of existing classes, which is not safe, or trying to do something for custom classes you own that are direct subclasses of NSObject, which probably is.

Almost all NSStrings you see in practice are instances of a private subclass, and that subclass allocates space for the string inline with the object. Like, instead of containing a pointer to a char*, the character data comes right after the ivars in the object. The extraBytes parameter in NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone) is there for purposes such as this.

So on the one hand, yes, you can pull tricks like that. On the other, you need to know you're doing it with your stuff. If you try to do something like that with the private subclass of NSString (which is private, so you're only going to interact with through runtime introspection), you're probably going to conflict.

There are a few public cocoa classes that also do stuff like this, so you're best off if your classes inherit directly from NSObject. NSLock is one. The layout in memory for a custom subclass of NSLock looks like { isa, <ivars of NSLock> <ivars of subclass of NSLock> <more NSLock stuff, space reserved using the extraBytes parameter> }.

Also, just for the heck of it, note that +alloc calls +allocWithZone:, and +allocWithZone: is the more common override point.

Ken
Oh, but I just saw what you're trying to do. Okay, for that, it's fine to play with it for fun, but I wouldn't try it for actual use. That's the kind of hacking that you regret and wish you just sucked it up and did it the normal way. It'd be nice to have general purpose hacking like that in the frameworks, where it can, say, correctly adapt to garbage collection if gc is added to the phone. You can do the ivar to ivars thing, or you might want to look at objc_getAssociatedObject/objc_setAssociatedObject. These basically automate having a dictionary for extra stuff in your object.
Ken
On the other other hand, if this is to speed up the compile/run/debug cycle and what you ship in your app won't be using it, sounds like fun, go for it. :-) Though.. you might want to look at ZeroLink, <http://www.cocoadev.com/index.pl?ZeroLink>. This was intended to speed up dev and worked as you describe, reloading code and such. Apple gave up on it though - too often the solution to some weird problem was "turn off zerolink".
Ken
I up voted this for the allocWithZone: and NSLock example, but I can't really accept this just yet as it doesn't meet the criterium of things that don't call through allocWithZone. Also, this would be for the basis of production code, so I'll probably not do it this way due to your NSLock example -- it would end up breaking any NSLock subclass that uses the technique.
Jared P
The private subclass of NSString does not go through +allocWithZone:. -[NSString alloc] returns an object of (private class) NSPlaceholderString. initWithBytes:length:encoding: on NSPlaceholderString doesn't return the receiver. It allocates storage for a new string without calling +[NSObject allocWithZone:] and returns it - it has to do that to get the extra bytes, see?
Ken
Here's one way of thinking of it: Is whatever you're doing something that could be done independently by two different subsystems, or would the two implementations conflict? If they conflict, what you're doing is not safe. It's the kind of thing that would have to be built into the frameworks.
Ken
A: 

Sounds like you are trying too hard to manage memory. Let the OS dynamically allocate memory when you create an object. If you are using too much, the OS will send a notification that you are getting close to the limit. At that point you can dealloc stuff you don't need anymore.

If you need so much memory that you have to use tricks, your implementation may need rethinking at the core level instead of trying to fit your square design into the round hole of the iPhone OS.

Just my opinion based on the info you provided.

ExitToShell
You clearly have no idea what this question is asking, and absolutely no familiarity with the function in question or it would be immediately clear that it uses the exact same amount of memory as any normal technique, specifically because it is often what's used to implement alloc in cocoa, or you think I'm an idiot and don't realize this for myself
Jared P