When should we use two-dimensional pointer in objective c - objective-c

I want to know when should we use two-dimensional pointer in objective c. I read a article about the runtime mechanism. The implementation details of method objc_msgSend is as follows:
Any NSObject objective has a attribute of isa which will point to the corresponding Class object.
#interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
Class objective is as follows:
struct objc_class {
Class isa;
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists; // Method list of the class
Cache cache;
struct old_protocol_list *protocols;
}
The question I want to ask is that why methodLists is two-dimensional pointer, what if we use one-dimensional or do not use pointer, can sb explain this question to me?Thanks in advance.
The struct old_method_list is as below:
struct old_method_list {
void *obsolete;
int method_count;
/* variable length structure */
struct old_method method_list[1]; //The address of the first Method
};
OK, I read another article about why old_method_list use two-dimensional pointer, the reason is that, it may point to an array.My another question is that for struct old_method method_list[1], the comment is "The address of the first Method", but method_list is an old_method array which length is 1. How it can store address?
I solved this question by reading another article.
The array struct old_method method_list[1] is dynamic, it can be changed by adding elements(methods) to it.

Because it points at array of pointers at old_method_list.
Update for old_method_list.
old_method_list * can point not just at old_method_list. It also can point at for example:
struct old_method_list_with_10_methods
{
struct old_method_list list;
struct old_method method_list[9];
};
Or if you need dynamic size:
old_method_list* list = malloc(sizeof(old_method_list) + (n-1) * sizeof(old_method));
list->method_count = n;
It's such variable length structure.

Related

Casting an (NSString *) to (int *)?

I have an NSString.
NSString *str;
And I need to store it in a struct.
struct {
int *s;
} st;
And set it.
st.s = str;
So, how should I go about retrieving it?
return (__bridge_retained NSString *)st.s;
I've tried the above, and it gives the error: Incompatible types casting 'int *' to 'NSString *' with a __bridge_retained cast.
Answered the question. Simply define the NSString in the struct like this.
struct {
__unsafe_unretained NSString *s;
} st;
Thanks, Carl Veazey!
To store an Objective-C object in an struct you have a couple of options, the one I see most is to store it in the struct as __unsafe_unretained and then maintain a strong reference to it elsewhere.
From the "Common Issues While Converting a Project" section of the ARC Transition Notes:
If using Objective-C objects is sub-optimal, (maybe you want a dense
array of these structs) then consider using a void* instead. This
requires the use of the explicit casts...
They seem to imply __bridge is the way to cast void * to id but are not 100% clear on this.
The other option, which makes more sense to me personally and I've seen more often I think:
Mark the object reference as __unsafe_unretained. ... You declare the
structure as: struct x { NSString * __unsafe_unretained S; int X; }
Hope this helps!

Struct array in struct [Objective-c]

Let say I have these:
typedef id Title;
typedef struct{
Title title;
int pages;
}Book;
So far, the code is okay. But the problem is here:
typedef struct{
int shelfNumber;
Book book; //How can I make this an array of Book?
}Shelf;
Like what I have stated in the comment in the code, I want to make Book as array so that it can hold a number of books. Is that even possible? If it is, how can I do it?
typedef struct{
int shelfNumber;
Book book[10]; // Fixed number of book: 10
}Shelf;
or
typedef struct{
int shelfNumber;
Book *book; // Variable number of book
}Shelf;
in the latter case you'll have to use malloc to allocate the array.
Note that you could use a flexible array member to achieve this effect:
typedef struct {
int shelfNumber;
size_t nbooks;
Book book[];
} Shelf;
This is an elegant use case because you have the simplicity of use of a static array but if you need to allocate a Shelf object of size sz, you only have to do one malloc:
Shelf *mkShelf(int num, size_t sz) {
Shelf *s = malloc(sizeof(Shelf) + sz * sizeof(Book));
if (!s) return NULL;
*s = (Shelf){ num, sz };
return s;
}
Compound literals and flexible array members that I used above are C99 features, so if you program with VC++ it might not be available.

Returning a 2D C array from an Objective-C function

I want to do achieve something like this in Objective-C
+(int[10][10])returnArray
{
int array[10][10];
return array;
}
However, this gives an "array initializer must be an initializer list" compiler error. Is this at all possible?
You can't return an array (of any dimension) in C or in Objective-C. Since arrays aren't lvalues, you wouldn't be able to assign the return value to a variable, so there's no meaningful for such a thing to happen. You can work around it, however. You'll need to return a pointer, or pull a trick like putting your array in a structure:
// return a pointer
+(int (*)[10][10])returnArray
{
int (*array)[10][10] = malloc(10 * 10 * sizeof(int));
return array;
}
// return a structure
struct array {
int array[10][10];
};
+(struct array)returnArray
{
struct array array;
return array;
}
Another way you can do it with objective C++, is to declare the array as follows:
#interface Hills : NSObject
{
#public
CGPoint hillVertices[kMaxHillVertices];
}
This means the array is owned by the Hills class instance - ie it will go away when that class does. You can then access from another class as follows:
_hills->hillVertices
I prefer the techniques Carl Norum describes, but wanted to present this as an option that might be useful in some cases - for example to pass data into OpenGL from a builder class.

Returning C struct array

Hello stackoverflow fellow members?
Struct Declaration in class A
struct PointSprite
{
GLfloat x;
GLfloat y;
GLfloat size;
Color4f color;
} ParticleSystems[MAXIMUM_PARTICLES_ON_SCREEN];
// I generally put some stuffs in ParticleSystem array.
// for ex) struct PointSprite *ps = &ParticleSystems[index];
// and it works well on the class A, but I want to get class B to access this array.
My question is, how am I suppose be return the array of 'ParticlelSystems' array so that other class can access to it? I have tried below code to return the pointer, but compiler gives me a warning.
- (struct ParticleSystems *) commitParticles
{
struct ParticleSystems *ptr = &ParticleSystems; // it said, assigning incompatible pointer type
return ptr;
}
Or should I need to allocate the 'ParticleSystems' array? Please help ! Thanks
If you are creating the array inside the function then you should dynamically allocate it using new and then return a pointer to it.
You cannot return arrays from a function, you will have to return a pointer to it.
Sample Code:
ParticleSystems* doSomethingInteresting()
{
ParticleSystems *ptr = new ParticleSystems[MAXIMUM_PARTICLES_ON_SCREEN];
//do the processing
return ptr;
}
The caller takes the ownership of the returned dynamically allocated array and needs to deallocate it to avoid memory leaks:
delete []ptr;
You can either return it, after allocating one, or you can fill one passed to you by the user. The latter leaves the responsibility to the user to provide a ParticleSystem to the method which receives the data. It can be a local array, or a malloced one.
- (void) commitParticles: (ParticleSystems *) sprites
{
// set members of the structs here
}
I prefer this kind of passing to returning a malloced array. Your mileage may vary.
You're getting the assigning incompatible pointer type compiler warning because your ptr declaration should be of type PointSprite *, not ParticleSystems *

Class dump and CFObjects

Does class dump get confused by CFObjects/structs? I used class dump on an application and one of the method's argument was a struct arg1 which is a BInstantMessage:
struct BInstantMessage {
void **_field1;
struct CFString _field2;
unsigned short *_field3;
struct DTextStyle _field4;
struct BUser *_field5;
struct BChat *_field6;
};
struct CFString {
void **_vptr$CFObject;
struct __CFString *mCFRef;
_Bool mIsMutable;
};
struct __CFString;
So, how can I get a CFStringRef or NSString* from this arg1? I am guess that class dump is replacing some CFStringRef by CFString definitions, but it's just a guess...
All I want is to get a CFStringRef from arg1 which is a BInstantMessage.
Thnaks!
The application is using a C++ wrapper for Core Foundation objects. the struct CFString in BInstantMessage is an object of this type. You want (NSString *)(arg1._field2.mCFRef).
The void **_vptr$CFObject field is the major hint here – it represents the vtable for a virtual superclass CFObject – combined with the common C++ m prefix naming convention.