Should I avoid creating lots of variables? - objective-c

I have two possibilities:
1) Store an object in a variable and use that variable in my code. But this uses memory to store the object right?
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
BOOL bool1 = [userDefaults boolForKey: key1];
BOOL bool2 = [userDefaults boolForKey: key2];
2) Don't store it in a variable and create it from scratch when I needed.
BOOL bool1 = [[NSUserDefaults standardUserDefaults] boolForKey: key1];
BOOL bool2 = [[NSUserDefaults standardUserDefaults] boolForKey: key2];
What would be recommended in this case? If there's a difference between objects then how would I know which one to use?

As far as the particular example you showed in your question is concerned, there's no practical difference between those two ways of getting the NSUserDefaults. Unless you are dealing with large data objects (like UIImages) you should be concentrating on the clarity and readability of your code. If it turns out that you have a memory issue during your testing, come back and find ways to use less memory later.

You haven't been very specific, as to what kind of data. But irregardless, the things variables point at are what consume memory, not the variables themselves.
As for the rest of your question, if you leave a comment explaining your application centered around this question, as in what part your system is doing at this moment, I'll edit this to reflect that answer.
EDIT: Someone else answered and was accepted before I could update my answer. See the accepted answer.

If the operation executed is a very performance heavy method, it might be a performance loss to redo it every time, when you simply can save the information.
I feel you have to choices
If you have a problem with allocated memory, redo it.
If memory problem isn't an important factor and the executed operation isn't that heave that you have a performance loss, redo it.
I believe that doing iPhone-apps, the memory is not that super critical (might be now with multitask however), it's more critical to have the workload in mind, i.e. try not to redo same work. But as said, it all depends on the situation.

The wording of your question suggests you may not fully understand C pointers. You're not "storing an object in a variable." The userDefaults variable in your first example is just a C pointer. The +standardUserDefaults method returns a pointer to the global user defaults object, which you assigned to userDefaults. In your second example, you retrieved a pointer to the object twice, once for each line.
The only real difference between the two is that in the second example, you're doing a redundant message-send to retrieve the object reference again. Your examples aren't performance-critical, but there are cases where you might want to cache a reference to an object to avoid sending redundant messages, such as in a loop. It all depends on the performance of your program.
If you're not comfortable with C pointers, definitely read up on them. It should clear up some things for you.

You are not using any more of your program's memory in the first example. The NSUserDefaults object will be stored on the heap either way, and the storage for the variable itself will either be a) a register, or b) on the stack. Registers don't take up any of your app's real memory, and the memory for the stack is already reserved.
Also, pointers take up a very small amount of memory — 4 bytes on 32-bit and 8 bytes on 64-bit platforms. A quarter of a million of them would take less than 1 MB. Individual scalars like this are the very last place you should be looking for memory savings.

Related

Does an auxiliary variable with a pointer have any performance/memory impact?

Does it?
I would normally pick this,
NSArray * monthsForChosenYear = [self monthsForYear:newChosenYear];
[self setMonths: monthsForChosenYear];
Over this,
[self setMonths: [self monthsForYear:newChosenYear]];
Mostly because it's easy to understand at a first glance. Where the second approach, not so much.
But what are really the implications of this? monthsForChosenYear, is just a pointer, but it must be stored somehow.
I'm not asking if the impact is so small that I wouldn't need to worry about it. But I am very curious about this.
Even a redirect to some document explaining in better detail would be nice.
Thank you in advance!
Nuno
A long answer to hopefully assuage your curiosity, and having curiosity is good! The performance & memory impact is either zero or miniscule. You wonder how the pointer is stored. When you type:
NSArray * monthsForChosenYear;
You are asking for a box (variable), to be referred to by the name monthsForChosenYear, to be allocated in local storage. This box will be automatically reclaimed when the enclosing method exits, and possibly earlier than that if the compiler figures out it is no longer needed. This box can hold a value of type NSArray *.
When you type:
NSArray * monthsForChosenYear = [self monthsForYear:newChosenYear];
You are asking for two things, it is just a shorthand for:
NSArray * monthsForChosenYear;
monthsForChosenYear = [self monthsForYear:newChosenYear];
and the second line calls a method and stores the returned value in your box named monthsForChosenYear. Finally when you type:
[self setMonths: monthsForChosenYear];
the value stored in the your box monthsForChosenYear is passed to a method. If you no longer use the box monthsForChosenYear the compiler may reclaim it, or it may wait till the end of the enclosing method or some other suitable point.
Compilers analyze the usage of boxes and optimise, sometimes they will not even allocate a box if it is determined one is not needed. The cost of allocating a box is infinitesimal.
*[Note: there are actually usually two kinds of local boxes. The second, often called a register, has an allocation cost which is usually even smaller than infinitesimal. Which kind of box is used is decided by the compiler.]*
When you type:
[self setMonths: [self monthsForYear:newChosenYear]];
You are asking for two methods to be called in one line and the value returned from the inner call ([self monthsForYear:newChosenYear]) has to be passed to the outer call. Where does the compiler store this result? The compiler in effect translates the above into:
NSArray *compilerTemporaryBox = [self monthsForYear:newChosenYear];
[self setMonths:compilerTemporaryBox];
and from the above you know how that goes. There is a small advantage to the compiler in that it knows how long compilerTemporaryBox is needed, so it doesn't need to figure it out, but that will not effect the compiled code.
So after all that the overall answer is it doesn't matter how you write it.
Furthermore the type of memory management you use: MRC, ARC or GC; will not effect the answer - the compiler will end up treating both your variants the same.
So go for the style you find best for you. HTH.
Clang is almost certainly smart enough to compile those two pieces of code to the same resulting machine code. There is no difference in terms of speed or memory issues.
Are you using ARC? Without ARC, with decent optimizer it will have no difference, but with ARC it might use additional retain/release.

CoreData and NSManagedObject memory state

this a question I always wanted to ask.
When I am running an iOS application in Profiler looking for allocation issues, I found out that NSManagedObject stays in memory long after they have been used and displayed, and the UIViewController who recall has been deallocated. Of course when the UIViewController is allocated again, the number is not increasing, suggesting that there's no leak, and there's some kind of object reuse by CoreData.
If I have a MyManagedObject class which has been given 'mobjc' as name, then in profiler I can see an increasing number of:
MyManagedObject_mobjc_
the number may vary, and for small amount of data, for example 100 objects in sqllite, it grows to that limit and stays there.
But it also seems that sometimes during the application lifecycle the objects are deallocated, so I suppose that CoreData itself is doing some kind of memory optimizations.
It also seems that not the whole object is retained, but rather the 'fault' of it (please forgive my english :-) ) because of the small live byte size.
Even tough a lot of fault objects would also occupy memory.
But at this point I would like some confirmation:
is CoreData really managing and optimizing object in memory ?
is there anything I can do for helping my application to retain less object as possible ?
related to the point above, do I really need to take care of this issue or not ?
do you have some link, possibly by Apple, where this specific subject is explained ?
maybe it is relevant, the app I used for testing rely on ARC and iOS 5.1.
thanks
In this SO topic, Core Data Memory Management, you can find the info you are looking for.
This, instead, is the link to Apple doc on Core Data Memory Managament.
Few tips here.
First, when you deal with Core Data you deal with an object graph. To reduce memory consumption (to prune your graph) you can do a reset on the context you are using or turn objects into fauts passing NO to refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag method. If you pass NO to that method, you can lose unsaved changes, so pay attention to it.
Furthermore, don't use Undo Management if you don't need it. It increases memory use (by default in iOS, no undo manager is created).
Hope that helps.

Why zone is always nil while implementing NSCopying?

It may be simple question, but why implementing NSCopying protocol in my class, I get zone == nil
- (id)copyWithZone:(NSZone *)zone
{
if (zone == nil)
NSLog(#"why this is allways nil");
(...)
}
This is called using this method for copy array with objects.
[[NSArray alloc] initWithArray:myArray copyItems:YES]];
Kevin's and Robin's answer is the most accurate. Oscar's answer is pretty close to correct. But neither the Gnustep documentation nor logancautrell's reasons for the existence of zones is quite correct.
Zones were originally created -- first NXZone, then NSZone -- to ensure that objects allocated from a single zone would be relatively contiguous in memory, that much is true. As it turns out, this does not reduce the amount of memory an app uses; it ends up increasing it slightly, in most cases.
The larger purpose was to be able to mass destroy a set of objects.
For example, if you were to load a complicated document into a document based application, tear-down of the object graph when the document was closed could actually be quite significantly expensive.
Thus, if all the objects for a document were allocated from a single zone and the allocation metadata for that zone was also in that zone, then destruction of all objects related to the document would be as cheap as simply destroying the zone (which was really cheap -- "here, system, have these pages back" -- one function call).
This proved unworkable. If a single reference to an object in the zone leaked out of the zone, then your app would go BOOM as soon as the document was closed and there was no way for the object to tell whatever was referring to it to stop. Secondly, this model also fell prey to the "scarce resource" problem so often encountered in GC'd system. That is, if the object graph of the document held onto non-memory resources, there was no way to clean up said resources efficiently prior to zone destruction.
In the end, the combination of not nearly enough of a performance win (how often do you really close complex documents) with all the added fragility made zones a bad idea. Too late to change the APIs, though, and we are left with the vestiges.
A NULL zone just means 'use the default zone'. Zones aren't used by the modern Objective C runtime anymore and cannot be used with ARC at all.
See documentation
NSZone was deprecated a long time ago. The fact that it's still in method signatures (e.g. +allocWithZone: and -copyWithZone:) are for backwards compatibility.
NSZone is now an undocumented class because it is quite old, its purpose was to allocate objects on the heap using the same set of virtual memory pages. However it is mostly not used anymore, but since it was used before, that parameter is still there for backwards compatibility.
Zone is a legacy from the old days when computers had 8 megs or less of RAM.
Check this out (3.1.2 Memory Allocation and Zones):
http://www.gnustep.org/resources/documentation/Developer/Base/ProgrammingManual/manual_3.html
There is also a good discussion of this over on cocoa builder (well it was on the cocoa dev mailing list) from about 10 years ago. This is exactly what #bbum was saying.
http://www.cocoabuilder.com/archive/cocoa/65056-what-an-nszone.html
Apparently this used to be documented in the Apple docs, but it was changed at some point since 2007-06-06.
http://www.cocoadev.com/index.pl?NSZone

NSString pointer: theoretical questions after study

I have questions about the NSString pointer. I wanted to get to the bottom of this and actually tried to create a theory to obtain full understanding based on multiple information retrieved from then net. Please believe me when I say that I have not been lazy, and I actually read a lot, but I was still left with uncertainties and questions. Can you please confirm / deny when good / wrong, and I've put additional questions and doubts which are indicated by (?).
Here we go:
If I consider this very basic example:
NSString *sPointer = [[NSString alloc]initWithString:#"This is a pointer"];
[sPointer release];
My starting point was: The compiler reserves RAM memory for a pointer type and this memory (which also has an own address) contains the memory address (hexadecimal - binary) of the memory where another variable is stored (where it points to). The actual pointer would take up about 2 bytes:
1) First some general issue - not necessarily linked to objective C. The actual questions about the NSString pointer will come in point 2.
A string is a "string of characters", where 1 character takes a fixed amount of memory space, let's say 2 bytes.
This automatically means that the memory size occupied by a string variable is defined by the length of the character string.
Then I read this on Wikipedia:
"In modern byte-addressable computers, each address identifies a single byte of storage; data too large to be stored in a single byte may reside in multiple bytes occupying a sequence of consecutive addresses. "
So in this case, the string value is actually contained by multiple addresses and not by a single 1 (this already differs from what I read everywhere) (?).
How are these multiple addresses contained in 1 pointer in reality? Will the pointer be divided into multiple addresses as well?
Do you know what component in a computer actually identifies and assigns the actual address "codes"?
And now my actual questions;
2) In my example, the code does 2 things:
It creates a pointer to the address where the string variable is stored.
It also actually saves the actual "String variable": #"This is a pointer", because otherwise there would be nothing to point to;
OK, my question; I wondered what really happens when you release the pointer [sPointer release]; are you actually releasing the pointer (containing the address), or are you also releasing the actual "string variable" from memory as well?
I have learned that when you delete the reference, the memory where the actual variable is stored will just be overwritten at the time the compiler needs memory so it does not need to be cleared at that time. Is this wrong?
If it is correct, why do they say that it's really important to release the NSString pointer for performance reasons, if you just release the pointer which will basically contain only a few bytes? Or am I wrong, and is the memory where the actual variable is stored in fact also cleared at once with the "release" message?
And finally also: primitive datatypes are not released, but they "do" take memory space at the moment of declaration (but not more than a common pointer). Why shouldn't we release them in fact? What prevents us from doing something like: int i = 5, followed by [i release]?;
I'm sorry - a lot of questions in 1 time! In practice, I never had problems with it, but in theory, I also really want to fully understand it - and I hope that I'm not the only one. Can we discuss the topic?
Thank you and sorry for the bother!
Maybe I'm wrong but I just read yesterday that pointers usually take 4 bytes. That answers none of your questions but you seem really interested in this so I figured I would mention it.
I think the source of your confusion is that you are confusing primitives with Objective-C classes. Objective-C classes (or objects to be exact, instances of classes) can accept messages (similar to method invocations in other languages). retain is one such message. This is why an Objective-C NSString object can receive the retain message but not a primitive like an integer. I think that's another one of your confusions. retain and release etc. are not Objective-C language constructs, they're actual messages (think methods) you send to objects. That is why they apply to Objective-C objects but not to primitives like integers and floats.
Another similar confusion is that what you read about how strings are stored has more to do with C-style strings, like char *name = "john". However, when you create a pointer to an NSString, that points to an NSString instance, which itself decides how to handle storing the actual string bytes/characters. Which may or not be the same way that C strings are stored.
data too large to be stored in a single byte may reside in multiple bytes occupying a sequence of consecutive addresses. " So in this case, the string value is actually contained by multiple addresses and not by a single 1 (this already differs from what I read everywhere) (?). How are these multiple addresses contained in 1 pointer in reality?
In C for example, the pointer would point to the address of the first character in the string.
OK, my question; I wondered what really happens when you release the pointer [sPointer release]; are you actually releasing the pointer (containing the address), or are you also releasing the actual "string variable" from memory as well?
You are sending the release message to the NSString instance/object. This is important to note to avoid further confusion. You are not acting upon the pointer itself, but upon what the pointer is pointing to, which is the NSString object. So you are not releasing the pointer itself. After sending the object the release method, if its reference count has reached 0, then it will handle deallocating itself by deallocating everything it stores, which I imagine includes the actual character string.
If it is correct, why do they say that it's really important to release the NSString pointer for performance reasons, if you just release the pointer which will basically contain only a few bytes?
So yeah, you're actually sending the release message to the string instance and it handles how to deallocate itself if it has to. If you were to simply erase the pointer so that it no longer points at the string instance, then you simply will no longer know where/how to access the data stored at that location, but it won't make it magically disappear, the program won't automatically know that it can use that memory. What you're hinting at is garbage collection, in which, simply put, unused memory will automatically be freed for subsequent use. Objective-C 2.0 does have garbage collection but as far as I know it's not enabled on iOS devices yet. Instead, the new version of iOS will support a feature known as Automatic Reference Counting in which the compiler itself takes care of reference counting.
Sorry if I didn't answer all of your questions, you asked a ton :P If any of my information is wrong please let me know! I tried to limit my answer to what I felt I did know.
"Or am I wrong, and is the memory where the actual variable is stored in fact also cleared at once with the "release" message?" The memory IS NOT CLEARED, but goes into the free memory pool, so that it does in fact reduce the memory print of the program. If you did not release the pointer you would continue to "hog" memory until you consume all the virtual memory available and crash not only your program but potentiality the system as well.
How are these multiple addresses contained in 1 pointer in reality?
Will the pointer be divided into multiple addresses as well? Do you
know what component in a computer actually identifies and assigns the
actual address "codes"?
From the perspective of the programmer (take note of this), the pointer on itself is usually a 4-byte number that represents the offset from start from the memory (32-bits, in 64-bit you can have addresses up to 8 bytes). The thing is that this pointers points to the start of whatever is being stored, and that's it.
In C for example, the original strings used a NULL (\0) terminated strings to identify when a string ended (Try doing a printf() on C with a non-zero ended string, and it will print whatever is in memory until it finds a zero). This of course is pretty dangerous, and one has to use functions like strncpy (notice the "n") indicating that you should manually input the number of chars from the offset until it ends.
A way to circumvent this is storing the used space in the start of the memory address, something like
struct
{
int size;
char *string;
}string;
That stores the size to prevent any issues. Objective-C and many other more abstract language implement in their own way how to handle memory. An NSString* is quite an abstract class to know what happens behind the scenes, it probably inherits all its memory managing from the NSObject.
The whole point I'm try to get is that a pointer contains the starting address, and you can jump from byte-to-byte from there (or jumps of a certain size), keeping in mind the total length of whatever you're storing to avoid doing nasty things like overflowing the stack memory (hence, the name of this site).
Now, how the computer gives this addresses is entirely up to the Operating System, and your logical memory address you use in all your programs is quite different from what the underlying implementation uses (physical memory address). Typically, you'll find that memory is stored in segmented units called "frames", and a used frame is called a "page". And the mapping in between physical and logical is done with a "[Page Table]"2.
As you can see, the software handles pretty much everything, but doesn't mean that there isn't hardware to support this, like the TLB, a cpu-level cache that holds recent memory addresses for quick access.
Also, please take my answer with a grain of salt, it's been a while since I studied these subjects.
OK, my question; I wondered what really happens when you release the
pointer [sPointer release]; are you actually releasing the pointer
(containing the address), or are you also releasing the actual "string
variable" from memory as well? I have learned that when you delete the
reference, the memory where the actual variable is stored will just be
overwritten at the time the compiler needs memory so it does not need
to be cleared at that time. Is this wrong? If it is correct, why do
they say that it's really important to release the NSString pointer
for performance reasons, if you just release the pointer which will
basically contain only a few bytes? Or am I wrong, and is the memory
where the actual variable is stored in fact also cleared at once with
the "release" message?
When you release, you're just decreasing the memory count of the object. What you mean is what happens when it's dealloced (when the count reaches zero).
When you dealloc something, you're basically saying that the space where it has been reserved it's now free to be replaced by anything else requesting memory (through alloc). The variable may still point to a freed space, and this causes problems (Read about dangling pointers and leaks).
The memory might be cleared, but there's no guarantees.
I hope this clears all the doubts, as all of them spawn from your confusion about memory freeing.
And finally also: primitive datatypes are not released, but they "do"
take memory space at the moment of declaration (but not more than a
common pointer). Why shouldn't we release them in fact? What prevents
us from doing something like: int i = 5, followed by [i release]?;
The thing is C has two main things going (actually, a lot more): The Heap that stores memory that has been requested with alloc (or malloc in C), and these require to be freed. And the Stack, which holds local variables, that die when the function/block ends (the stack pops the function call).
In your example, the variable i has been locally declared within its scope, and it's contined in the stack. Trying to peform a dealloc/free (also, the variable i won't respond to release, nor dealloc, as it's not an object) won't work, as is not the type of memory which requires to be freed.
I suggest you going back to C before trying to tackle what Objective-C does, because it's hard to have a clear idea how the imperative programming works with all the nice abstractions like release and dealloc.
For the sake of the forum, I will make a brief and simplified summary of your answers as a conclusion. Thanks to all of you for this extended clarification, the mist disappeared! Don't hesitate to react in case you want to add or rectify something:
Rectification: a pointer on the Mac takes 4 bytes of memory space and not 2.
The pointer *sPointer points to an instance of the NSString class and NOT directly to the memory where the chars are saved.
The NSString instance consists of a set of iVars in which there is a pointer iVar that points to memory allocated where the char variables that make up the string are stored (defined when using the initWithString: instance method).
[sPointer release]; The release message is not sent to the pointer itself, but to the instance of the NSString Object. You are not acting on the pointer itself, but on what the pointer is pointing to (!).
When sending the alloc message, the retain count of the NSString instance object is increased by 1. When sending a "release" message it doesn't mean that the concerned memory is literally being emptied, but it decreases the retain count by 1. When the retain count reaches zero, the compiler knows that the previously allocated memory is available again for re-use.
The way memories addresses are presented is decided by the operating system. The logical memory address used in programs is different from what the underlying implementation actually uses (physical memory address).
LOCAL variables (not necessarily primitive variables) are stored in the Stack memory (unlike objects instances who are stored in the Heap memory). What this means is that they will be destroyed automatically at the end of a function (they are automatically removed from the stack). More info on the memory constructs stack and heap can be found in several threads that clarify the use and difference in their own way. e.g.. What and where are the stack and heap? / http://ee.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html
Before I answer the points, you start with a false premise. A pointer takes up more than 2 bytes on a non-16 bit system. On the Mac, it takes up 4 bytes for a 32 bit executable, and 8 bytes in a 64 executable.
Let me note that the following is not entirely accurate (for optimization and some other reasons, there are several kinds of internal representations of strings and the initXXX functions decide which is instantiated), but for the sake of use and understandingof strings, the explanation is good enough.
An NSString is a class (and a rather complicated one as well). A string, i.e. an instance of that class, contains some administrative ivars and one that is another pointer which points to a piece of allocated memory big enough to at least hold the bytes/code points that make up the string. Your code (the alloc method, to be precise) reserves enough memory to contain all the ivars of the object (including the pointer to the buffer) and returns a pointer to that memory. That is what you store in your pointer (if initWithString: doesn't change it -- but I won't go into that here, let's assume it doesn't). If necessary, initWithString: allocates the buffer large enough to hold the text of the string and stores its memory in the pointer for it, inside the NSString instance. So it is like this:
sPointer NSString instance buffer
+---------------------------+ +-----------------+ +------+
| addr of NSString instance | ----> | ivar | +-> | char |
+---------------------------+ | ivar | | | char |
| ivar (pointer) | --+ | char |
| ivar | | char |
| etc... | | char |
+-----------------+ | char |
| etc. |
+------+
In the case of a hard-coded, literal string like #"Hello", the internal pointer only points to that string, which is already stored in the program, in readonly memory. No memory has to be allocated for it, and the memory can't be freed either.
But let's assume you have a string with allocated contents. release (either coded manually, or invoked by an autorelease pool) will decrement the reference count of the string object (the so called retainCount). If that count reaches zero, your instance of the NSString class will be dealloced, and in the dealloc method of the string, the buffer holding the string text will be released. That memory is not cleared in any way, it is only marked as free by a memory manager, which means it can be re-used again for some other purpose.

Accessing NSUserDefaults Often

During a logic process in my app, I need to access the user preferences frequently, and a bunch of times 10~15 to determine what needs to be processed and how. May this question is not about performance, but about doing it correctly.
Currently I'm doing a [[NSUserDefaults standardUserDefaults] valueForKey:...] each time I need to request a value. Is this correct? I think that "saving" the user defaults as an ivar could reduce extra work, but then I wonder if this won't have sync problems, like if the user changes the preferences and they get updated only if the app is restarted (so the user defaults object is recreated).
Is there any better way?
Don't worry about it, it's extremely fast and I do not believe there is a better way, it's the way the class is meant to be used.
The NSUserDefaults class caches the values internally so the lookup is extremely fast. The overhead of [NSUserDefaults standardUserDefaults] vs an instance variable is so small that you wouldn't even notice it if you did it 5 million times in your code.
The only proper way of optimising this would be by improving your logic, caching the values you're using yourself with a pointer rather than the dictionary that NSUserDefaults basically is etc.
You won't have any problem if you save the defaults object to an ivar. Notice it's a singleton and its pointer won't change.
Do the values in the user defaults change over time during this logic process?
If not, you could access each value that you'll need throughout the process once at the start and store the results in local variables.
Then you can use those variables as many times as you like without having to hit the user defaults reading the data each time.
However, if those values are being changed while your logic process is ongoing, then accessing them from the defaults is probably the only way.
In terms of performance, accessing it 10-15 times isn't going to have any adverse effect. If you were accessing it 10-15 times per second for a prolonged period of time, then you might encounter some responsiveness issues.