I'm creating tests where I have to make sure 2 different NSDate instances are really two different instances of allocated memory. So I have this example code:
NSDate *date1 = [NSDate date];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:0 sinceDate:date1];
XCTAssertEqualObjects(date1, date2);
XCTAssertNotEqual(date1, date2);
The first assert should compare object values using "isEqual", and it's working great!
The second assert should compare pointers using "==". The bizarre thing is that it sometimes fails randomly, telling me that both pointers have the same value (ie, they are pointing to the same allocated memory).
As I'm allocating twice, it is supposed to be different memory areas... So why do I have this test failing randomly sometimes? Maybe XCode is reusing memory areas somehow?
You can't reliably force the creation of separate objects. Some classes may use tagged pointers. The set of classes doing that can change over time with releases of the OS. A tagged pointer really just encodes the value of the object into a pointer-sized value. It doesn't allocate any memory. By definition, any two objects represented as tagged pointers whose values are equal will have equal "addresses".
Also, an init method is just a method. It can return any object it wants. There's no rule that it has to return the receiver. It can release the alloced object it is sent to (self) and return a different object. If it can determine that an existing object (such as the parameter you're passing to -initWithTimeInterval:sinceDate:) meets its needs, it may return that object (with an extra retain). This sort of thing is common in immutable value classes, like NSDate or NSString.
You're going to have to reconsider your supposed need to "make sure 2 different NSDate instances are really two different instances of allocated memory".
Related
NSString *cachePath= [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
cachePath= [cachePath stringByAppendingPathComponent:#"nerd.archive"];
// Load the cached channel
RSSChannel *cachedChannel= [NSKeyedUnarchiver unarchiveObjectWithFile:cachePath];
NSLog(#"unarchived data- %# %p, x value- %d",cachedChannel,cachedChannel,cachedChannel.x);
// if one hasn't already been cached, create a blank one to fill up
if (!cachedChannel) {
cachedChannel= [[RSSChannel alloc] init];
NSLog(#"cachedChannel initialised- %# %p",cachedChannel,cachedChannel);
cachedChannel.x=5;
}
In the above code-snippet, the pointer variable cachedChannel is assigned with the return value of unarchiveObjectWithFile: message. Now obviously in the first run, this would return nil but the pointer will be initialized later on in the “if-statement”. Lets say the cachedChannel var is something like
cachedChannel= [RSSChannel:0X123ff]
After the code has gone through its first run, the object assigned to cachedChannel would become serialized.
When i run the test project the second time and the unarchiveObjectWithFile: message is passed so that the serialized object is returned and assigned to the cachedChannel pointer var, it shows up as a different object with a different object-id.
Instead of cachedChannel pointing to [RSSChannel:0X123ff] object, it is now holding some other object like [RSSChannel:0X445ee]
How could this be possible?? Shouldn’t the object that was serialized before be the one to be unarchived later on with the same object-id residing in the same heap memory location?
How could this be possible?? Shouldn’t the object that was serialized before be the one to be unarchived later on with the same object-id residing in the same heap memory location?
Not at all. This is, as you say, happening later. And at this later time, the memory situation is completely different. Think of it this way: if you have code that creates an object from scratch, e.g. [[MyObject alloc] init], and you run the app today and then quit it and run the app again tomorrow, those two instances of MyObject, even though they play the very same role in the life of the app, will have two different memory addresses.
Moreover, what we are creating as we unarchive the object is a different instance from the one that was archived - identical, in whatever ways you have specified while archiving / unarchiving, to the original, but a different instance. Think of it this way: archive-unarchive is an elaborate way of making a copy of the object - and two copies of one instance are, obviously, two different objects.
After all, you could archive the object, hang on to the original, and immediately unarchive the archived object. That would be two different objects. But they could not possibly live at the same memory address!
It sounds like you may be trying to use the memory address as some sort of unique identifier. Beware of that. If a thing needs a unique identifier, give it a unique identifier as a property. Don't rely on the memory address at runtime for anything, except during debugging to confirm that two instances are one and the same instance.
So I am busy reading an objective-c book by Big Nerd Ranch. I'm on chapter 17 at the moment and managed to complete the required challenge at the end of the chapter. However, I just have two question that I would like to understand.
In the following bit of code - StockHolding is a custom class that has instance variables and the stocks (an array) points to three instances of stockholding with values setting its stock value and cost in dollars.
At first I tried to access the array to get the data from the objects it pointed to - but it seems that was not going to work as the array doesn't know what data its objects contain - just where they are in memory, right?
What I want to know is why was it necessary to create a new instance of stockholding (holdings) in this for loop to access those variables?
How does the new instance of stockholding know what the values of my stocks are?
for (StockHolding *holdings in stocks){
NSLog (# "%# has %d shares. Cost: $%.2f. Stock value: $%.2f", [holdings stockName],[holdings numberOfShares], [holdings costInDollars], [holdings valueInDollars]);
}
I'm going to try have a guess here to see if maybe I understand it a little better?
We create an instance of our class in the for loop so that we have access to its instance methods and variables - then we use the stocks array to get the variables from those objects in the array?
I may be completely off.. :(
Any advice?
stocks is an array having the objects of type StockHolding
So in order to access all values in the array and print the values.You need to get all the StockHolding instance inside the array we use for ...in method
note Here new instance is not created just new reference is made to the memory that is in the array so that you can access it and use it
Absolutely no new instances are created in the for loop at all. Since Objective-C objects are always represented as pointers, one variable != one instance. The holdings local variable inside the loop is assigned the pointer to the element of the array which is currently being enumerated upon each iteration. It's just a "reference" to an already existing object.
You're not creating new instances. You're iterating through existing instances.
Presumably in [CODE] you have created the objects and added them to the NSArray. The for loop just gives them to you one at a time. You name it holdings, do something with it, then grab the next.
That's all.
In Objective-C objects are typeless. Any message can be sent to any object. Code like [holdings stockName] means "send the message 'stockName' to the object 'holdings'". So the Objective-C runtime will inspect the object to see whether it implements that message. If so then it'll pass execution into the implementation.
The type of your object makes no difference to how processing will occur at runtime.
An NSArray stores anything that conforms to the NSObject protocol. So it can hold any old mix of objects. The same goes for the other collections.
Although you could write all your code without mentioning a single object type, you usually don't because if you say which type of objects you're dealing with then the compiler can perform some sanity checks. That makes you less likely to write broken code.
So the code:
for (StockHolding *holdings in stocks)
just means "let me do something to every object in the collection stocks and don't give me any compiler warnings when I treat them like instances of StockHolding". They may actually be other classes. If they're other classes that implement stockName, numberOfShares and the rest then your code will work perfectly.
So, for example:
NSMutableArray *arrayOfStrings = [NSMutableArray array];
[arrayOfStrings addObject:#"34.3"];
[arrayOfStrings addObject:#"19.8"];
float total;
for(NSNumber *number in arrayOfStrings)
{
total += [number floatValue];
}
Will compile and work perfectly — not because the strings are actually converted to numbers but because both classes implement floatValue to return a float. So each NSNumber *number is actually an NSString, and if you tried to call, say, isEqualToNumber: on any of them you'd raise an exception because that isn't implemented by strings. But telling the compiler you're going to act as if they're numbers means you don't get a warning for using floatValue and when the runtime spots that the object implements floatValue execution continues as usual.
The for..in loop is used for fast enumeration.
This
for (StockHolding *holdings in stocks)
{
}
won't create any new object, it takes one object from array and cast it to the specified type and assign it to the specified variable.
Means:
Takes the object from the array . Equivalent to [stocks objectAtIndex:index];
Assign it to the specified object. Equivalent to StockHolding *holdings = [stocks objectAtIndex:index];
Note that Only the reference is used (assignment) there is no object is allocated.
NSArray *array = [dictionary objectForKey:#"field"];
and
NSArray *array = [[NSArray alloc] initWithArray:[dictionary objectForKey:#"field"]];
I see both kind of approaches very frequently in objective C code.
When tried to understand, I found both of them used in similar situation too, which makes contradiction. I am not clear on when I should use 1st approach and when 2nd one?
Any idea?
Detailed explanation and useful references are moms welcome.
First off, those two examples are doing slightly different things. One is retrieving something from an existing dictionary and one is creating a new array by retrieving something from an existing dictionary (the value of that key is an array).
But, if you're asking the difference between getting objects by alloc vs. convenience methods. ([NSString alloc] init vs [NSString stringWith ...), by convention, you own anything that you call alloc, new copy or mutableCopy on. Anything that you call that is not those, is autoreleased.
See the memory guide here. Specifically, look at the rules.
Getting an autoreleased object means it will go away at some point in the near future. If you don't need to hold onto outside the scope of that function, then you can call autorelease on it or use one of the convenience methods that's not alloc, etc...
For example:
// my object doesn't need that formatted string - create the autoreleased version of it.
- (NSString) description {
return [NSString stringWithFormat:#"%# : %d", _title, _id];
}
// my object stuffed it away in an iVar - I need the retained version of it. release in dealloc
- (void) prepare {
_myVal = [[NSString alloc] initWithFormat:"string I need for %d", _id];
}
In the first example, I created a convenience methods for others to call, my class doesn't need that object beyond the scope of that method so I create the autoreleased version of it and return it. If the caller needs it beyond the scope of his calling method, he can retain it. If not he can use it and let it go away. Very little code.
In the second example, I'm formatting a string and assigning it to an iVar variable that I need to hold onto for the lifetime of my class so I call alloc which will retain it. I own it and releasing it eventually. Now, I could have used the first version here and just called retain on it as well.
You have a fundamental misunderstanding of allocations versus instance methods.
The first example, NSDictionary's -objectForKey method, returns id, not an instance of NSDictionary, therefore it does not allocate or initialize the variable.
The second, however is the classic retain part of the retain-release cycle.
The two methods are fundamentally equal (if we are to assume that array is alloc'd but empty in the first, and nil in the second), and both get ownership of the array object. I would go with the second, as it guarantees a reference, and it's shorter.
What I think you're confusing this with are new and convenience methods. Convenience methods (like NSNumber's +numberWithInt:, NSString's +stringWithFormat:, and NSMutableArray's +array), return an autorelease instance of the class (usually). New takes the place of alloc and init in just one word.
I've always seen that we use an intermediary object, for example, creating an array to fill in another array:
characters = [[NSArray alloc] initWithObjects:#"Antony", #"Artemidorus", #"Brutus", nil];
play.characters = characters;
[characters release];
with characters being an NSArray in the object play.
I saw the same thing with a #property and its self: we did not add the new items directly into this property, just as we don't directly fill in characters in the example above. Is this only about "style"?
This is not a matter of style.
play.characters is a property, and that can "contain" an existing array or nil, but even if it "contains" an existing array, you can't change the contents of an NSArray, so you'll have to create a new one and assign that to the property.
Assigning to a property will, if all was declared well, cause its setter method to run (which could be created by the compiler, if you used #synthesize, or written by you, in code) and that will take care of removing any existing array, assigning the new one and retaining it.
There is actually only one array in play in that little piece of code.
It is not the array that is intermediate, but the variable holding a pointer to it - in this case the variable characters.
This is what happens:
The expression
[[NSArray alloc] initWithObjects:#"Antony", #"Artemidorus", #"Brutus", nil]
allocates an object and initialises it with three NSStrings (which are themselves objects, but let's leave that out for a moment). The initialisation also includes an increment of the retain count, so it is one from the get-go.
This newly created object lives at a given position in memory, say 0100H. This position is then stored in the variable characters. In C terms we say that characters is a pointer to the object.
Then the property #"characters" of the object play is set to point to the same position in memory as the local variable characters. There are therefore now two variables (of which one is also a property) that point to the same object, or, if you prefer, to the same position in memory. If the property is of type retain, this will automatically increment the retain count of the object, so it is now 2.
With the release message in the last line, the object decrements its retain count by one, so at the end of this code snippet, the object is pointed to by the play.characters property, and it has a retain count of one.
To be really clean, this code should probably set the local variable to nil, to avoid confusion between variables holding pointers to the object and the retain count.
All this was meant to show that there really is only one array in play here, but two variables that point to it. So there are not as many computer resources being wasted as it might seem at a first glance.
If you wanted to do it all in a single line, you could write something like this:
play.characters = [[[NSArray alloc] initWithObjects:#"Antony", #"Artemidorus", #"Brutus", nil] autorelease];
but the exact working of this is less clear as it involves one of those mysterious autoreleases, i.e., a release that is handled automatically and postponed to some later stage.
This is a long description, but I hope it sheds some light on what is going on.
Hi I need to initialize an NSObject at a particular location that I specify(through a void* pointer, for example). For a little bit of context, I am writing a sqlite3 aggregate function. To keep temporary results from this function, I have to call a sqlite3_aggregate_context function, which allocates a block of memory for me. I want to store an NSDecimalNumber at this location.
So far I have tried two approaches:
1)allocWithZone, by doing:
void *location = sqlite3_aggregate_context(...); //returns a block of allocated memory of a certain size
NSDecimalNumber *num = [[NSDecimalNumber allocWithZone:NSZoneFromPointer(location)] initWithInt:0];
This does not work because NSZoneFromPointer returns nil. Docs say that the arguments to this function must be a previously allocated pointer, which it is. I dont know if this means allocated using NSZoneMalloc/Calloc.
2)
id location = sqlite3_aggregate_function(...);
location = [[NSDecimalNumber alloc] init];
but this causes some kind of infinite recursion when freeing the memory...not sure what the deal is. A screenshot here:
http://dl.dropbox.com/u/3002073/Public%20Sync/sqlitefunctionissue.png
Any suggestions will be greatly appreciated!
You can't really determine reliably where an object is going to be created in memory. The NSZoneFromPointer fails for you because the sqlite3 API is not using zones to allocate its resources.
If you want to be able to pass a specific location, you should do so using a pointer to the object (so you are storing a pointer to a pointer basically). You can then read this information from your aggregate function and update it accordingly. Just make sure that you don't simply let your object be freed at the end of the call without taking care to release it (or you'll have a leak).
So, for example, you could do something like:
NSDecimalNumber** numberLocation = sqlite3_aggregate_context(...);
*numberLocation = [[NSDecimalNumber alloc] initWithDouble:25.0];
You now have a reference to your object stored in your special memory area and can access it any time:
NSDecimalNumber* storedNumber = *numberLocation;
NSDecimalNumber* computedNumber = [[NSDecimalNumber alloc] initWithDouble:[storedNumber doubleValue] * someComputation];
[storedNumber autorelease];
*numberLocation = computedNumber;
On the other hand, I agree with Mark; maybe this immutable class isn't the best solution to your problem?
Your first version is simply not going to work. NSZoneFromPointer only works when passed a pointer allocated from a zone. It's used so you can allocate an object from the same zone as some other object.
The second version ought to work, though it's difficult to tell without more context. What are you passing to sqlite3_aggregate_context as the size of the memory to allocate? And how are you freeing that memory when you're done?
The second version doesn't work because the "id" type is actually a pointer, so you're pointing it at the memory returned by sqlite3_aggregate_context(), then pointing it at the memory returned by alloc/init. You really need to store a pointer-to-pointer to get that to work the way you want.
NSDecimalNumber is an immutable class, so calling -init on it (as opposed to -initWithDecimal:) is just going to get you some default value. What sort of code are you using to replace the NSNumber with new values as the function progresses?
More to the point, why use NSDecimalNumber at all, as opposed to a C integer, or double, or whatever?