Subclassing memory allocations question - objective-c

I have a basic question about subclassing a class with objects:
#interface Myclass : NSObject{
UIImage *image;
NSString *string;
ParticleSystem *system;
Object *obj;
Object2 *obj2;
}
If I subclass this MyClass class, and I initialise only a few of these objects defined in the superclasses header, what happens to all the other unallocated definitions in terms of memory?
The reason I ask, I have a class with many, many definitions and i've been subclassing it for simplicity sake, but my subclass only needs a fraction of these definitions.
Is it worth just subclassing NSObject and redefining the needed variables rather than subclassing MyObject?
Thanks,
Oliver.

They take up space, but only a pointer's worth (4 bytes on the iPhone) per variable.
The better reason for separating these out into separate classes is that it sounds like you don't have a very clean division of responsibilities. A class should be composed of some logical grouping of data and operations on that data. Things not having to do with the class's role probably belong elsewhere.

Each of those variables is a pointer so they are taking up the storage required to point to a memory address. (4 bytes on iPhone)
Is iPhone OS 64 bit or 32 bit?
If each of the sub classes only needs a small subset, then only include those in the base class (rather than copying and redefining in those in every class). If some of those subclasses require the full set, then you can also have a class hierarchy (layered sub-classes). It's impossible to know without seeing the concrete design.

If you just have pointers in the class definition (eg, SomeClassName* somePointerName;) then each pointer takes up one pointer location in each of your objects (4 bytes on iPhone).
Though it's occasionally convenient to do what you're doing, you're missing out on many of the benefits of object-oriented programming -- you're basically just making use of Objective-C's storage management while coding cruddy C.

Related

Multilevel inheritance problems

In my app I am using 2-3 levels of inheritances as per requirement, so I wanted to ask is this good idea to use so many levels of inheritance in iOS, where memory is big constraint and whether this will affect performance and what about memory since if I allocate 1 object actually it will allocate 3 objects, including Base?
Assuming you have a class hierarchy as below where classes to the right are subclasses of those to the left:
NSObject->Subclass1->Subclass2
If you then instantiate Subclass2
Subclass2 *instance = [[Subclass2 alloc] init];
Only one Subclass2 object will be created. Separate objects for Subclass1 and NSObject are not created. As Subclass2 inherits all of the ivars from the two superclasses, it will, however, have sufficient RAM allocated to store the ivars from Subclas1 and NSObject.
If you look at the CocoaTouch framework, there are many objects that have several superclasses between them and NSObject.
When considering RAM usage, more important than the number of superclasses a subclass has is the number and size of the ivars and the number of individual objects you create.

Subclass NSArray in Objective-C

I need to have a class, which has all methods of NSArray, which behave the same way, but 2 methods are modified.
I want to override these 2 methods in my custom class:
1) countByEnumeratingWithState:objects:count:
2) objectAtIndex:
After hours of research I don't see any reasonable way to do that, because:
I don't want to use category, because not all NSArray instances should have the modified behaviour. (Plus that throws warnings)
I don't want to re-write all initializers plus all arrayWith... methods + the primitive methods + implemented my own storage (because this functionality is already implemented in Cocoa, right? Why would I re-implement all the functionality of a class that is already there?)
If I have my custom class inherit NSObject and use NSArray as storage in an ivar, then all NSArray's methods are not available when programming in Xcode (even if I can forward them to the NSArray ivar)
I had some success overwriting the method implementations on demand by using method_setImplementation(...), but still can't figure out a way to have dynamically a class created at runtime, which then will have custom implementation of the 2 methods I mentioned.
Looking forward to your ideas! Thanks
Mantra: If something is hard (or seems like it requires more code than is necessary), it is likely that your design is counter to the design principals of the iOS / OS X frameworks. It may yield a better solution to revisit your design.
To answer the original question, if you want to subclass NSArray (or NSMutableArray), you need to implement the primitive methods, no more, no less.
The primitive methods are the methods declared in the #interface of the class itself. I.e.:
#interface NSArray : NSObject
- (NSUInteger)count;
- (id)objectAtIndex:(NSUInteger)index;
#end
And for NSMutableArray:
#interface NSMutableArray : NSArray
- (void)addObject:(id)anObject;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
#end
If you subclass NSMutableArray and implement the above 7 methods (the two from NSArray, too), you will have an NSMutableArray subclass that is compatible -- assuming your methods are correctly implemented -- with all APIs that consume mutable arrays.
This is because of the way class clusters are designed. The public classes are abstract; are never directly instantiated. They provide a primitive interface that contains the class's core functionality and then concrete implementations of all the other non-primtive API (save for the initializers, see below) that are implemented in terms of the primitives. Concrete, private, subclasses then override all the primitives and some of the non-primitives to provide optimal behaviors for specific configurations.
I want to have an NSArray instance for a library I'm working on and I
want to have it working transparently for the users of my library. Ie.
for them should be no difference between using a normal NSArray and
the modified class I'll be providing. Ie. it's a storage concern,
which the end users should not be concerned with and the interface
should remain the same as NSArray - therefore loosing all init methods
is not really an option at that point.
The initialization methods are not a part of the primitive interface to NSArray. You are adding a requirement above and beyond "make a class compatible with NSArray / NSMutableArray" as defined by the documentation. Nothing wrong with that, just pointing it out.
The reason why this is the case is because it is exceptionally rare to subclass the collection classes to provide the kind of business logic you describe. Collections are very generic in their behavior whereas such business logic that conditionalizes collection behavior would be done in a class that manages the overall model layer object graph.
If you really want to do this, provide an implementation of whatever init* methods you want, calling through to your wrapped generic instance as needed. There isn't anything so special about the implementations of the initializers that you are going to lose much in doing so.
No need to implement all of them, either. Implement one or two and #throw a descriptive exception on the rest.
If you do decide to forward the ones that accept var-args, you can't directly because there are no va_list accepting methods. Instead, you'll want to convert the va_list of arguments into a language array (i.e. id[] foo = malloc(... * sizeof(id));) and pass it to initWithObjects:count:.
Some other comments:
What you are doing [provide full NS*Array interface in a subclass] seems hard because it is not a common pattern and the framework designers saw no need to create a design to support it. Custom behaviors at the primitive collection levels are almost always better implemented at a higher level within the object graph. Almost always.
method_setImplementation() and dynamic class creation is academically interesting, but pretty much never a solution. Obviously, mucking with the NSArray or NSMutableArray classes (or the concrete implementation classes) is going to blow up the rest of the frameworks that rely upon standard behavior. Beyond that it, it is a pattern of dynamic OO composition that is not really intended to be used in Objective-C; it'll be a pain in the ass to maintain.
Instead of subclassing NSArray why not create a new class based on NSObject that contains an NSArray?
Then you can use all the functions of the NSArray and add your own methods that will do custom actions with it?
Or do you NEED an NSArray?

struct or class

I'm developing an iPhone 3.1.3 application.
I have a class, called Object2D, with fields and methods; which represent a shape. Object2D has a field that represents its size, and another field that represent its type.
Now, I need another class called Pattern, which is a set of shapes. In Pattern I'm going to have an array of shapes. From these shapes I only need their size, their type and their location inside pattern, I don't need any method.
I'm wondering it is better to have a new struct that represent a shape instead of using Object2D class.
I ask this because I think on memory performance. I'm not sure, but struct are smaller than classes and maybe it's better to use them instead of classes.
What do you think?
If you're looking at memory use, the difference is truly negligible in almost every situation. Objects are one pointer bigger than an equivalent struct.
The greater difference is in how you can use them. Objects can have methods and hierarchies and interact with the rest of Cocoa. With structs, you need to make custom functions for each struct type or hack together a pseudo-object system. On top of that, arbitrary structs don't interact well with the rest of Cocoa (Touch). For example:
If you store objects in them, you have to be very careful to do your own memory management correctly
You can't store them in NSArrays without creating an object wrapper (since NSArray is an array of objects)
You can't hook structs up in Interface Builder — it doesn't know anything about them
You can't do KVO or KVC with structs
In general, if you're working with a Cocoa-like framework, objects are a good default choice. Use structs once you've decided you really need them.
Objective-C classes are in fact structs, and, provided the instance variables are laid out in the same order as the structure members are, the only difference in size is the 4 or 8 bytes of NSObject's isa variable.
NOTE: the answer above assumes the legacy Objective-C runtime, without the use of #property and #synthesize directives, which could potentially affect their size.

Do all objects occupy similar amounts of memory? Objective-c

If I make my object a subclass of UIViewController, does it use substantially more memory than if it is a subclass of NSObject? A ballpark figure for how much more overhead is used by subclassing a complex class vs a simple one would be great. edit: or a way to figure out the difference myself.
You can imagine that an objective-c object is just a C structure that looks like this:
typedef struct {
Class isa;
} NSObject;
An instance of that structure would take 4 bytes on a 32-bit system. Since it's composed of a single pointer - Class is similar to id.
A subclass of NSObject, MySubclass with one 'char' instance variable would look like this:
typedef struct {
Class isa;
char singleInstanceVariable.
} MySubclass;
A subclass simply has all of the instance variables of its super class at the beginning, plus its own at the end. You can see this in the debugger by typing 'p *object' in the console.
MySubclass's size would be 5 bytes on a 32-bit system. One pointer, plus one char. So, an object's size is the size of all of it's instance variables added together. One important thing to know is that an object's size is only related to its instance variables. It isn't impacted by the number of methods it has. Those methods don't cost any extra memory as more instances are instantiated. Methods have a fixed initial cost.
Another thing to consider is that objects usually have pointers to other objects as instance variables. For example, let's say every UIView has an NSMutableArray to reference its subviews. That array might be 12 bytes when empty. So an empty UIView would be the size of all of the variables in a UIView, which would include 4 bytes for the pointer to an array, plus you might also account for the 12 additional bytes used by the actual array instance. That's all just accounting though, the array and the view are two distinct objects, but the view isn't really usable without the array.
Lastly, most allocations are rounded up to some quantum in order to make the malloc implementation faster and to satisfy some constraints of the architecture of the machine so that pointers are properly aligned. Also an object's instance variables might have empty padding in between them similar to structure padding
That depends on the number and nature of the superclass's instance variables. NSObject has one ivar, the isa pointer. UIViewController has about 30 ivars, most of them pointers (you can look the list up in UIViewController.h).
So any subclass of UIViewController will take up as much memory as is needed to store all those ivars and all ivars of its superclasses (UIResponder (no ivars) and NSObject (one ivar)).
This calculation does not take into account the actual memory that is used by the objects these instance variables reference when initialized, of course. For example, a fully initialized view controller may hold on to a view object that takes up a considerable amount of memory.
Try class_getInstanceSize([MyClass class]);. Roughly speaking, the memory usage of an instance will be this value rounded up to a multiple of sixteen bytes. Of course, this doesn’t include overhead of any associated objects (see objc_setAssociatedObject) or allocations the class makes.
In short, yes, but probably not enough that you need to worry about it unless you're planning on instantiating tens thousands of them.
The object will allocate memory for each of its ivars and its methods. The amount of memory needed depends on the C types... they all vary according to the datatype what's being stored.
The amount of memory used depends on how the object is instantiated, presented on screen, and interacted with. For example, a subclass of NSObject will not have any interaction with the user's touches.
You can always attach you application with the Instruments Allocations performance tool to compare the difference.

Why subclass NSObject?

What is the purpose/use of NSObject in Objective-C? I see classes that extend NSObject like this:
#interface Fraction : NSObject
In C++ or Java, we don't use any variables like NSObject even though we have preprocessor directives and import statements in both Objective-C and Java.
Why do classes explicitly inherit from NSObject in Objective-C? What are the consequences of not declaring inheritance from NSObject?
We use NSObject to explicitly state what a given class inherits from. I'm not sure about C++, but in Java there's something similar - the Object class. The only difference is that Java doesn't require that classes explicitly descend from Object - the language assumes anything that doesn't have a specified parent class descends from Object. Objective-C is different because it allows you to define different root classes - you are allowed to make a class that doesn't inherit from NSObject.
An example of such a different root class is NSProxy.
Have a look at the GNUstep NSObject source, it shows how the methods interact with the objective-c runtime through C functions.
+ (id) allocWithZone:(NSZone*)z
{
return NSAllocateObject(self, 0, z);
}
- (void) dealloc
{
NSDeallocateObject (self);
}
+ (BOOL) isSubclassOfClass: (Class)aClass
{
return GSObjCIsKindOf(self, aClass);
}
Since object-oriented languages have the concept of an inheritance, in any inheritance hierarchy there is a root class. In Java, the default parent class (if none is provided) is java.lang.Object, whereas in Objective-C, if you don't explicitly declare a parent class, you don't get one. Essentially, your class becomes a root class itself. This is a common mistake among Objective-C newcomers, since you normally want to inherit from NSObject in such cases.
While often problematic and puzzling, this actually allows quite a bit of flexibility, since you can define your own class hierarchies that act completely differently from NSObject. (Java doesn't allow you to do this at all.) On the other hand, unless you know what you're doing, it's easy to get yourself into trouble this way. Fortunately, the compiler will provide warnings if you call a method not defined by a class with no declared parent class, such as those you would normally expect to inherit from NSObject.
As for the "use" of NSObject, check out the documentation of the NSObject class and NSObject protocol. They define common methods used for object allocation, memory management, comparison, hashing, printing descriptions, checking class membership, querying whether objects respond to a selector, etc. Basically, NSObject is "good for" providing the core functionality of Objective-C objects free of charge.
All classes don't necessarily inherit from NSObject but it is the core for many of the classes because it provides things like alloc, retain, and release.
NSObject is the root class of all classes. In my estimation, it's 3 most basic functions are to allocate and initialize memory for you (alloc & init), as well as provide a description function.
Objective-C is all about objects sending messages to other objects -- so NSObject exists to provide that basic functionality.
If this sounds strange to you, you may wish to read more about programming paradigms, particularly object-oriented programming....In a nutshell, however, Objective C is a simple extension to the C language. C gets you the ability to program computer memory, numbers, and characters, but do anything else (like use strings, or show views, for example) you need the extension part, and NSObject is the beginning of that extension.
It may be a useful exercise to pick a class (like NSString, or any for that matter), and follow it's superclasses back to NSObject, to see what functionality each class added.
Hope that helps...
NSObject
The root class of most Objective-C class hierarchies, from which
subclasses inherit a basic interface to the runtime system and the
ability to behave as Objective-C objects.
From Apple documentation - https://developer.apple.com/documentation/objectivec/nsobject.
Basically, most of OOP programming languages explicitly or implicitly specify base class or base functionality. Otherwise you cannot build system where objects communicate with each other. Properties, memory management, message sending mechanism are partly or completely provided or supported by NSObject. Apple provide parts of the Objective-C implementation - https://opensource.apple.com/source/objc4/objc4-723/runtime/NSObject.mm.auto.html, where it's possible to see what is actually inside NSObject.
Also because Objective-C is a language from C-family, so compiler and linker needs to calculate how to layout object in memory and where put and find methods, that's only possible if you know how each of the classes/instances lays in memory and where. In case of Objective-C all base classes (NSObject, NSProxy, etc) have specification of that, so it's possible to calculate their size and add on top all inherited stuff - https://clang.llvm.org/compatibility.html#objective-c.
Consequently compiler don't let to leave a class without base class. So in the end class inheritance should lead to one of the root classes. Here is the error that appears if you don't specify it (from Xcode):
Class 'ClassWithoutBaseClass' defined without specifying a base class