Struct array in struct [Objective-c] - 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.

Related

When should we use two-dimensional pointer in 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.

why cannot I use struct like this?

why cannot I use struct like this?
typedef struct { unsigned char FirstName; unsigned char LastName; unsigned int age; } User;
User UserNick = {Nick, Watson, 24};
NSLog(#"Your paint job is (R: %NSString, G: %NSString, B: %u)",
UserNick.FirstName, UserNick.LastName, UserNick.age);
I mean I have used a struct like this for sure:
typedef struct {unsigned char red; unsigned char green; unsigned char blue; } Color;
Color carColor = {255, 65,0};
NSLog(#"Your paint job is (R: %hhu, G: %hhu, B: %hhu)",
carColor.red, carColor.green, carColor.blue);
If you want to use C strings you need the following code:
typedef struct { unsigned char *FirstName; unsigned char *LastName; unsigned int age; } User;
User UserNick = {"Nick", "Watson", 24};
NSLog(#"Your paint job is (R: %s, G: %s, B: %u)",
UserNick.FirstName, UserNick.LastName, UserNick.age);
C strings are char *. C string literals need to be in quotes. %s is the format specifier for C strings.
One other suggestion - start field names (and variables names) with lowercase letters.
And since you are working with Objective-C, you would probably end up being better off if you make User a real class instead of a struct. Then you can use properties and proper memory management. The names could be NSString instead of C strings. This makes it easy to store the objects in collections and do other useful things that are hard with a plain old struct.
In your definition, FirstName is an unsigned char which means it is a variable that can hold only one char as its value. However, Nick is a string, namely an array of chars.
One could do
typedef struct {
unsigned char * FirstName;
unsigned char * LastName;
unsigned int age;
} User;
User Nick = {"Nick", "Watson", 24};

How does typedef-ing a block works

In C/Obj-C, we do a typedef like this typedef int MYINT; which is clear.
Doing typedef for a block -typedef void (^MyBlock) (int a);
Now, we can use MyBlock.
Shouldn't it be like - typedef void (^MyBlock) (int a) MyBlock; similar to #define?
How the syntax works?
See Declaring a Block Reference in "Blocks Programming Topics":
Block variables hold references to blocks. You declare them using
syntax similar to that you use to declare a pointer to a function,
except that you use ^ instead of *.
So
typedef void (^myBlock) (int a);
defines a the type of a block using the same syntax as
typedef void (*myFunc) (int a);
declares a function pointer.
See e.g. Understanding typedefs for function pointers in C for more information about function pointers.
Also from "Blocks Programming Topics", creating a type for blocks should be like this:
typedef returnType (^blockName)(argument1, argument2, ...)
Below is a very simple practical example:
typedef float (^MyBlockType)(float, float);
MyBlockType AddTwoFloat = ^(float a, float b) {return a + b;};
MyBlockType MultiplyTwoFloat = ^(float a, float b) {return a * b;};
float c = AddTwoFloat(1, 2); //c = 3
float d = MultiplyTwoFloat(1, 2); //d = 2

Using struct with Objective-C methods

I'm writing a simple game, and thought it would be much easier to use structures. However, I can't declare methods that need the structs.
How could I use a struct as an argument to an Objective-C method and get an object of the struct returned?
//my structure in the .h file
struct Entity
{
int entityX;
int entityY;
int entityLength;
int entityWidth;
int entityType;
bool isDead;
};
//And the methods i'm trying to use
-(BOOL)detectCollisionBetweenEntity:Entity ent1 andEntity:Entity ent2;
-(struct Entity)createEntityWithX:int newEntityX andY:int newEntityY, withType:int newEntityType withWidth:int newEntityWidth andLength:int newEntityLength;
You can use structs exactly like you would expect, your problem seems to be with the syntax of methods:
struct Entity
{
int entityX;
int entityY;
int entityLength;
int entityWidth;
int entityType;
bool isDead;
};
//And the methods i'm trying to use
-(BOOL)detectCollisionBetweenEntity:(struct Entity) ent1 andEntity:(struct Entity) ent2;
-(struct Entity)createEntityWithX:(int) newEntityX andY:(int) newEntityY withType:(int) newEntityType withWidth:(int) newEntityWidth andLength:(int) newEntityLength;
Types in methods need to be in parens, and you have to refer to struct Entity instead of Entity unless you typedef (in plain Objective-C, Objective-C++ might let you do it)
Structs are used as parameters in Objective-C all the time. For example the CGRect from Apple's CGGeometry Reference
struct CGRect {
CGPoint origin;
CGSize size;
};
typedef struct CGRect CGRect;
You just have to create a type for your struct, which can be done in the same way as Apple, or could have been done as
typedef struct CGRect {
CGPoint origin;
CGSize size;
} CGRect;
So in your case:
typedef struct
{
int entityX;
int entityY;
int entityLength;
int entityWidth;
int entityType;
bool isDead;
} Entity;
Should allow you to define
-(BOOL)detectCollisionBetweenEntity:(Entity) ent1 andEntity:(Entity) ent2;
-(Entity)createEntityWithX:int newEntityX andY:int newEntityY, withType:int newEntityType withWidth:int newEntityWidth andLength:int newEntityLength;

Change enum values at runtime?

Is there a way to assign values to enums during runtime in objective c?
I have several enums and want each of the enum to have certain value.
The values could be read from a xml file. Is there a way to do this?
Unfortunatley, #Binyamin is correct, you cannot do this with an enum. For this reason, I usually do the following in my projects:
// in .h
typedef int MyEnum;
struct {
MyEnum value1;
MyEnum value2;
MyEnum value3;
} MyEnumValues;
// in .m
__attribute__((constructor))
static void initMyEnum()
{
MyEnumValues.value1 = 10;
MyEnumValues.value2 = 75;
MyEnumValues.value3 = 46;
}
This also has the advantage of being able to iterate through the values, which is not possible with a normal enum:
int count = sizeof(MyEnumValues) / sizeof(MyEnum);
MyEnum *values = (MyEnum *) &MyEnumValues;
for (int i = 0; i < count; i++)
{
printf("Value %i is: %i\n", i, values[i]);
}
All in all, this is my preferred way to do enums in C.
No, enums information is erased at compile time.