Use ObjectiveC objects with malloc - objective-c

I try to create double pointer to simulate two dimensions array to hold the ObjectiveC object
Here is my declare syntax:
BlockInfo.m
#implement BlockInfo
-(void)someMethod{
}
#end
Other.m file
BlockInfo** pt = (BlockInfo**)malloc(sizeof(BlockInfo*)*10);
for(int i=0; i<10; i++){
pt[i] = (BlockInfo*)malloc(sizeof(BlockInfo)*3);
}
Here are the errors:
Pointer point to non-const type 'BlockInfo*' with no explicit ownership
Application of 'sizeof' to interface 'BlockInfo*' is not supported on the architecture and platform
Any help would be appreciated!

First of all you should really recheck whether you need ids in a C array. You have done it? Okay, do it again. You still need it? Okay, go on reading.
1.
What's wrong in your code is that you try to allocate the instance with malloc(). Never do that. Use +alloc-init, use +new, use a convenience allocator, but always use the framework for instance creation. Beside the fact that you give the RTE the chance to register instance creation, it is easier to you, because otherwise you have to set up the proper infrastructure of the instance. And there is no reason to do instance creation via C's malloc().
2.
Beside this you can store instance references (expressions of type id) to C objects ("variables"). To be more precise: You do that all the time, because every reference to an instance is a C object ("variable"). Therefore you can use C arrays, too.
A type is a retainable object owner type if it is a retainable object pointer type or an array type whose element type is a retainable object owner type.
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#id20
The reason for this is that C does not allow copying the whole array (as with structs), so you have to assign every single reference, what you do in your code.
But there are some caveats:
ARC cannot really follow the instance's ownership, when the array loses its extent. So set every element to nil explicitly, before the extent of the array is lost.
Do not use memcpy() or a similar function to change values of the elements. ARC has no chance to release the reference stored before or to retain the newly stored instance.
When you assign a new reference to an element, the old one is released. Therefore at the very beginning you have to fill the whole array with nil. (For local variables this is done automatically. That's the reason, why strong local vars are initialized.) calloc() does this automatically for you.
Typically the elements shall be strong references. You have to specify this explicitly.
BTW: Stylistic: You can malloc an C array of type id*, because all object references has equal size. (And has to, obviously). You shouldn't cast a malloc()'s return value.
So something like this should work:
__strong BlockInfo** pt = calloc(10, sizeof(id));
for(int i=0; i<10; i++){
pt[i] = [BlockInfo new];
}
…
for(int i=0; i<10; i++){
pt[i] = nil;
}

It seems that you tried to compile with ARC enabled. Try passing -fno-objc-arc as a compiler argument.
Please read the Objective-C Runtime Reference or the Objective-C Runtime source code for further details.

Related

Why does the runtime allow the assignment of an NSDictionary out of an array into an NSString variable?

Consider this code:
NSMutableArray *array = [[NSMutableArray alloc]init];
for(int i = 0; i < 5 ; i++)
[array addObject:[[NSDictionary alloc]init]];
NSString *poisonedString = [array objectAtIndex:0];
In this above snippet, I have an array and I am inserting some dictionary objects into this array. While all this is fine and dandy, when I get the dictionary object from the array and put it into an string object, it is not causing any cast exceptions! The program runs smoothly and then crashes only when we do dictionary operations on the poisonedString! Why is this so? Why doesn't the Objective-C runtime see the type mismatch and raise an exception at the assignment, when the dictionary object is put into poisonedString?
Objective-C is not type-checked at runtime at all unless those checks are explicitly added. What is done at runtime is method lookup in response to a message, and in this the type of the target is not considered only whether the target has an matching method.
At compile time the Clang compiler does as much static type-checking of the Objective-C additions to C as it can to provide the programmer with warnings when types are incorrect. However the programmer can always bypass those warnings with little difficulty if they really wish to, but it is generally ill-advised to do so.
Whenever the type of something is "lost", e.g. when it is put into a collection which allows for any type of object and later extracted, then the compiler cannot provide any meaningful help. It is up to the programmer to add code to check the actual runtime type and then cast the value to the determined type. While the cast itself does nothing at runtime at compile it informs the compiler of the determined type and that allows it to do better type checking and produce better warnings.
You test the type of something with the method isKindOfClass, so the outline template is:
id someVar = ...
if ( [someVar isKindOfClass:[SpecificType class]] )
{
SpecificType *typeKnownVar = (SpecificType *)someVar;
// now use typeKnownVar and compiler will do static checking where possible
}
else
{
// deal with someVar not being of SpecificType
}
HTH
In a nutshell, NSArray supports inserting any type of object into it. If you look at the documentation you can see a generic (id) object is returned when using objectAtIndex:
- (id)objectAtIndex:(NSUInteger)index
With that in mind you can't expect the compiler to know ahead of time what type your object is when you get it from the array.
Because first of all you are not casting :) I can't see any cast, and second of all, welcome to Objective-C, this is what they call a Dynamic Language, and you can read more here
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html
Now back to your code, the arrays are not generic so you can add whatever items of whatever classes you want in the same array and when you get the item, you don't need to cast it, the compiler trusts you :D now if you try to send a message (or as you named it do some operations), it'll throw a runtime exception, so simply if you are in the situation where you don't know if it's an NSString or an NSDictionary, just use the below code to check the type of the object.
if ([array[0] isKindOfClass:[NSDictionary class]]) {
// Do whatever you want
}
else if ([array[0] isKindOfClass:[NSString class]]) {
// Also do whatever you want
}
in NSArray class reference the documentation present that the return of ObjectAtIndex is an id
objectAtIndex:
Returns the object located at the specified index.
- (id)objectAtIndex:(NSUInteger)index
It is not possible to the compiler to know the type of object when your pointer is an id. It's normal that dump at executing time and not at compiling time.

Why do we create instances of classes in for loops?

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.

What points to a pointer?

As I understand pointers contain the address of data at another memory location?
When an app is running how is the location of pointers kept track of?
Why bother keeping track of the pointer, why not just directly keep track of address the pointer holds?
Additionally if I have the following code:
NSString *string = #"hello";
string = #"bye";
I am changing the value stored in the pointer named string (is it the pointer that is named string or the NSString object?) to the address of the new string ("bye"), right?
So how would I go about changing directly the object stored at the address held by the pointer?
(Also what is the correct terminology to use where I have used "keep track of"?)
Thanks
Why bother keeping track of the pointer, why not just directly keep
track of address the pointer holds?
Object references in objective C are actually pointers, so each time you use an object (such as NSString), you use a pointer to it - (NSString *)
I am changing the value stored in the pointer named string (is it the
pointer that is named string or the NSString object?) to the address
of the new string ("bye"), right?
Right.
So how would I go about changing directly the object stored at the
address held by the pointer?
In the case of such strings, they are immutable, and you can't change them, in case of other objects, you call their methods, or set their properties.
When an app is running how is the location of pointers kept track of?
Pointers are stored as any other variable; they typically take the same size as an unsigned long, but this is by no means guaranteed, just to give you an idea of how they are implemented. Compilers are free to do a huge variety of optimizations, so the pointers may be stored in memory, they may be stored in registers, or they may exist only as hypothetical entities if they are optimized away.
Consider the following code:
void foo(void) {
char *c;
char buf[100];
for (c=buf; c < buf+100; c++ {
c = '0';
}
}
In this case, the variable c is being used to write an ASCII 0 character to every character in the buf array. c may exist only in a register, because it does not live beyond this function. (There are better ways of writing this code.)
Consider the following code:
struct foo {
char name[10];
struct foo *next;
}
The member next in this case is a pointer to further struct foo objects -- say, a linked list of these things. These pointers must be stored in memory, because they are part of the contract of these objects -- they have to be there. There is no way around these pointers, either -- the objects they point to can be replaced with other objects on the programmer's whim. And, since the number of these objects is determined entirely at runtime, the compiler can't just keep track of the addresses in its symbol tables, as it would for stack-allocated variables.
So how would I go about changing directly the object stored at the address held by the pointer?
This is complicated by your example's use of "foo" strings in the code. These are saved in read-only memory in the process address space, so you cannot modify them. (Surprise!) If you initialize the strings with another method, you can modify the data via the pointer:
char *c = malloc(10);
strcpy(c, "hello");
c[0] = 'H';
printf("c: %s\n", c);
This will overwrite the h with H in the allocated space available via the c pointer. Accessing pointers as if they were arrays is the same re-writing the pointer access like this:
c[0] = 'f';
c+0 = 'f';
And, in fact, array accesses are pretty similar -- the name of the array is the same as a pointer to its first element.
It's a little complicated; the book Expert C Programming covers pointers in astonishing detail and is well worth the money.
Q : So how would I go about changing directly the object stored at the address held by the pointer?
Ans : start using NSMutableString if you want to change the content of memory location pointed by the your string pointer.
NSString is inmutable type ie you can't change the content but you can make the pointer to point somewhere else. "hello" to "bye" in your case.

Objective-C ARC and passing C arrays of objects

I'm sorry if this is a bit of a C-noob question: I know I need to swot up on my pointers. Unfortunately I'm on a deadline so don't have time to work through a whole book chapter, so I'm hoping for a bit more targeted advice.
I want to store some objective-C objects in a C array. I'm using ARC. If I were on the Mac I'd be able to use NSPointerArray instead, but I'm on iOS and that's not available.
I'll be storing a three-dimensional C array: conceptually my dimensions are day, height, and cacheNumber. Each element will either be a pointer to an objective-C object, or NULL.
The number of caches (i.e. the size of the cacheNumber dimension) is known at compile time, but the other two are not known. Also, the array could be very large, so I need to dynamically allocate memory for it.
Regarding ownership semantics, I need strong references to the objects.
I would like the whole three-dimensional array to be an instance variable on an objective-C object.
I plan to have a method that is - tableForCacheNumber:(int)num days:(int*)days height:(int*)height. That method should return a two-dimensional array, that is one specific cache number. (It also passes back by reference the size of the array it is returning.)
My questions:
What order should I put my dimensions so that I can easily return a pointer to the subarray for one specific cache number? (I think it should be first, but I'm not 100%.)
What should the return type of my method be, so that ARC doesn't complain? I don't mind if the returned array has an increased reference count or not, as long as I know which it's doing.
What type should my instance variable that holds the three dimensional array be? I think it should just be a pointer, since that ivar just represents the pointer to the first item that's in my array. Correct? If so, how do I specify that?
When I create the three-dimensional array (for my ivar), I guess I do something like calloc(X * Y * Z, sizeof(id)), and cast the result to the type for my ivar?
When accessing items from the three-dimensional array in the ivar, I believe I have to dereference the pointer each time, with something like (*myArray)[4][7][2]. Correct?
Will the two-dimensional array I return from the method be similarly accessed?
Do I need to tag the returned two-dimensional array with objc_returns_inner_pointer?
I'm sorry once again that this is a bit of a bad Stack Overflow question (it's too long and with too many parts). I hope the SO citizens will forgive me. To improve my interweb karma, maybe I'll write it up as a blog post when this project has shipped.
First off: while you don't have NSPointerArray, you do have CFMutableArrayRef and you can pass any callbacks you want for retain/release/description, including NULL. It may be easier (and performance is something you can measure later) to try that first.
Taking your points in order:
you should define your dimensions as [cacheNumber][days][height], as you expect. Then cache[cacheNumber] is a two-dimensional array of type id *[][]. As you've said performance is important, be aware that the fastest way to iterate this beast is:
for (/* cacheNumber loop */) {
for (/* days loop */) {
for (/* height loop */) {
//...
}
}
}
it should be of type __strong id ***: that's a pointer to a pointer to a pointer to id, which is the same as array of (array of (pointer to id)).
your ivar needs to be __strong id **** (!), because it's an array of the above things.
you guess incorrectly regarding allocating the array.. If you're using a multidimensional array, you need to do this (one dimension elided for brevity):
- (__strong id * * *)someArray {
__strong id * * *cache = (__strong id * * *)malloc(x*y*sizeof(void *));
id hello = #"Hello";
cache[0] = (__strong id * *)malloc(sizeof(void *)); //same for cache[1..x-1]
cache[0][0] = &hello; // for all cache[x][y]
return (__strong id * * *)cache;
}
correct, that is how you use such a pointer.
yeah, the two-D array works in the same way, sans the first dimension.
I don't think so, you're handing out __strong object pointers so you should be grand. That said, we're at about the limit of my ability with this stuff now so I could well be wrong.
Answering my own question because this web page gave me the missing bit of info I needed. I've also upvoted Graham's answer, since he was very helpful in getting my head round some of the syntax.
The trick I was missing is knowing that if I want to refer to items in the array via the array[1][5][2] syntax, and that I don't know the sizes of my array at compile time, I can't just calloc() a single block of data for it.
The easiest to read (although least efficient) method of doing that is just with a loop:
__strong Item ****cacheItems;
cacheItems = (__strong Item ****)calloc(kMaxZooms, sizeof(Item ***));
for (int k = 0; k < kMaxZooms; k++)
{
cacheItems[k] = (__strong Item ***)calloc((size_t)daysOnTimeline, sizeof(Item **));
for (int j = 0; j < daysOnTimeline; j++)
{
cacheItems[k][j] = (__strong Item **)calloc((size_t)kMaxHeight, sizeof(Item *));
}
}
I'm allocating a three dimensional array of Item *s, Item being an objective-C class. (I have of course left out the error handling code in this snippet.)
Once I've done that, I can refer to my array using the square brackets syntax:
cacheItems[zoom][day][heightToUse] = item;
The web page I linked to above also describes a second method for performing the memory allocations, that uses only one call to calloc() per dimension. I haven't tried that method yet, as the one I've just described is working well enough at the moment.
I would think of a different implementation. Unless it is a demonstrable (i.e. you have measured and quantified it) performance issue, trying to store Objective-C objects in plain C arrays is often a code smell.
It seems to me that you need an intermediate container object which we will call a Cache for now. One instance will exist for each cache number, and your object will hold an NS(Mutable)Array of them. Cache objects will have properties for the maximum days and height.
The Cache object would most easily be implemented with an NSArray of the objects in it, using simple arithmetic to simulate two dimensions. Your cache object would have a method -objectAtDay:Height: to access the object by its coordinates.
This way, there is no need at all to worry about memory management, ARC does it for you.
Edit
Given that performance is an issue, I would use a 1D array and roll my own arithmetic to calculate offsets. The type of your instance variable would be:
__strong id* myArray;
You can only use C multilevel subscripts (array[i][j][k]) if you know the range of all the dimensions (except the first one). This is because the actual offset is calculated as
(i * (max_j * max_k) + j * max_k + k) * sizeof(element type)
If the compiler doesn't know max_j and max_k, it can't do it. That's precisely the situation you are in.
Given that you have to use a 1D array and calculate the offsets manually, the Apple example will work fine for you.

Instance pointers in an array

I'm trying to save pointers of class instances into a mutable array. I'm able to do this but getting them back into use seems to be a problem. The next is how I inserted the pointers into the array:
Class *class = [Class new];
/* Do something with the instance */
[instanceArray addObject:class];
I am able to retrieve the wanted index from the array but when I try to access the instance variables etc. I only get compiler shouting at me or sometimes I get every variable as zero.
How am I supposed to get the instance back to use from the array? I know they are pointers but playing with them didn't seem to work.
Using addObject: the element is inserted at the end of the array. To retrieve it you can use -[NSArray objectAtIndex:]
Pointer arithmetic works in C since then your array is just a pointer to the first index, and array[i] is the same as *(array + i). In Objective-C this may still be done, however you're using an NSArray object. Now you don't have a pointer to the first object anymore, but to the instance of the class. To retrieve the objects stored in the array, you'll have to call the corresponding methods.
EDIT
So you are able to retrieve it from the array and then your pointer is not nil, so you do have access to the object. You know in Objective-C, all instance variables are private so you can't access them from outside. You'd have to declare them as properties first (please refer to the documentation). Also, when you declare a variable to be of type id, accessing a property with dot-syntax doesn't work, it will cause a compiler error.