Should I be creating a class instead of a struct so that I can put the data into an NSArray? - objective-c

Is it possible to create something like a C struct for Objective-C? I need to be able to use it in an NSArray so it cannot be a traditional struct. Right now I am declaring a whole class just to accomplish this and I was wondering if there is a simpler way.
What I currently have:
#interface TextureFile : NSObject
#property NSString *name;
#property GLKTextureInfo *info;
#end
#implementation TextureFile
#synthesize name = _name;
#synthesize info = _info;
#end
NSMutableArray *textures;
What I want to do:
typedef struct {
NSString *name;
GLKTextureInfo *info;
} TextureFile;
NSMutable array *textures;

It depends what kind of data you're using, the example you are using in your question seems okay for a struct.
If you need to store a C struct in an NSArray, which requires an object, you can convert the C-struct to NSValue and store it like that, you then convert back to its C struct type when you read it.
Check the Apple Documentation.
Given this struct:
typedef struct {
NSString *name;
GLKTextureInfo *info;
} TextureFile;
To store it:
TextureFile myStruct;
// set your stuct values
NSValue *anObj = [NSValue value:&myStruct withObjCType:#encode(TextureFile)];
NSArray *array = [NSArray arrayWithObjects:anObj, nil];
To read it again:
NSValue *anObj = [array objectAtIndex:0];
TextureFile myStruct;
[anObj getValue:&myStruct];

Related

Is this possible to get all the variable in property in objective c?

Is there any ways that I can find out how many variable to objective c object have?
For example:
#interface myObject:NSObject
{
}
#property(nonatomic, retain)NSString *firstString;
#property(nonatomic, retain)NSString *secondString;
I would like to know that object have firstString and secondString.
To get a list of all property names (old-fashioned instance variables need additional code) in anObject you can use this:
#import <objc/runtime.h>
u_int count;
objc_property_t *properties=class_copyPropertyList([anObject class],&count);
for(int i=0;i<count;i++)
{
NSString *propertyName=[NSString stringWithUTF8String:property_getName(properties[i])];
NSLog(#"Property: %#",propertyName)
}
free(properties);

objective-c struct properties are released before usage

I have a struct in my Objective-C code like this >
typedef struct {
__unsafe_unretained NSString *string1;
__unsafe_unretained NSString *string2;
__unsafe_unretained NSString *string3;
__unsafe_unretained NSString *string4;
__unsafe_unretained NSString *string5;
.
.
.
__unsafe_unretained NSString *string10;
} MyStruct;
In my model class I store these structs in an array declared
#property (nonatomic, strong) NSMutableArray *myStructArray;
I construct this in my .m file during runtime like this
NSMutableArray *myTempArray = [NSMutableArray array];
for (NSDictionary *jsonDict in jsonArray)
{
MyStruct stringsStruct = parseWithDictionary(jsonDict);
[myTempArray addObject:[NSValue value:&stringsStruct withObjCType:#encode(MyStruct)]];
}
myObject.myStructArray = myTempArray;
The problem is when I try to access this after parsing / constructing the inside objects are already deallocated & I received the error
-[CFURL length]: message sent to deallocated instance
Here is how I access the properties later by the way,
MyStruct myStruct;
[[myObject.myStructArray objectAtIndex:someIndex] getValue:&myStruct];
NSLog(#"%#",myStruct.string1); // << bam! crash
How do I fix this ? Is there a way to make sure the objects objects remain intact without deallocing until i'm done with it ? I'm using ARC & cannot remove with __unsafe_unretained hence.
You explicitly told ARC to get out of the way by using __unsafe_unretained and it's the only way to get a struct hold object values. This doesn't come without a price: you pay the memory management fee.
You manually have to retain/release any object you place in your structs by using CFRelease/CFRetain and this is very error prone.
Let me stress a point: __UNSAFE_unretained. The name hasn't been picked randomly.
My advice is: stop using structs and turn them into objects.
#interface MyClass : NSObject
#property (nonatomic, copy) NSString *string1;
#property (nonatomic, copy) NSString *string2;
...
#property (nonatomic, copy) NSString *string10;
#end
It's better under many point of views:
you get memory management "for free" with ARC
you can define convenience methods in the class
it's more idiomatic Objective-C wise

How do I publicly declare the keys to an NSDictionary?

I have defined a dictionary that I would like to pass around to various other objects. When they receive this dictionary, they need to know how it is defined so they can unpack it to get its values. I've been using #define's in my public header to define the keys. That way, I get edit-time compiler checking to ensure I don't use a bum key. But is there some other, more standard way to declare the interface to a defined dictionary so that other objects will get compile errors if they try to use undefined keys?
Better than #define is to use constant NSStrings. In your header:
extern NSString * const MyDictionaryFribbleKey;
(That's a constant pointer to an NSString.) And in your implementation:
NSString * const MyDictonaryFribbleKey = #"theFribble";
This is how the frameworks export constant strings. This won't stop the use of invalid keys, nothing will really do that (it's C, you can bypass anything), but it raises the bar higher.
Instead of using a dictionary why not use an object?
The example below shows that there really isn't much extra work involved. Plus you gain the advantages of actually using objects.
Object Set up
#interface MyClass : NSObject
#property (nonatomic, strong) NSString *myString;
#property (nonatomic, assign) CGFloat myFloat;
#end
#implementation MyClass
#synthesize myString = _myString;
#synthesize myFloat = _myFloat;
#end
Object use
MyClass *myClass = [[MyClass alloc] init];
// Set
myClass.myString = #"aa";
myClass.myFloat = 12.0f;
// Get
NSString *myString = myClass.myString
CGFloat myFloat = myClass.myFloat;
NSDictionary Set up
.h
extern NSString * const MYClassKeyMyString;
extern NSString * const MYClassKeyMyFloat;
.m
NSString * const MYClassKeyMyString = #"MYClassKeyMyString";
NSString * const MYClassKeyMyFloat = #"MYClassKeyMyFloat";
NSDictionary use
NSDictionary *myDict = [[NSMutableDictionary alloc] init];
// Set
[myDict setObject:#"aa" forKey:MYClassKeyMyString];
[myDict setObject:[NSNumber numberWithFloat:12.0f] forKey:MYClassKeyMyFloat];
// Get
NSString *myString = [myDict objectForKey:MYClassKeyMyString];
CGFloat myFloat = [[myDict objectForKey:MYClassKeyMyFloat] floatValue];
That's a pretty standard way. You can also enumerate the keys of a dictionary using the -enumerateKeys method.

Objective C initialization of a derived NSObject and further assignation

I'm not sure how to manage this, as objective-c is wierd enough for me
I'm have this derived class
#interface DoctorsSet : NSObject { NSString *tableid;
NSString *doctor_name;
NSString *doctor_surname;
NSString *city;
NSString *State;
NSString *phone; }
It has a custom constructor on which I'm initializing the properties as params...
THe problem is I have several functions that return this type, so how so I assign to a temporary local variable this type, or if my data comes from a NSMutableArray and I want to get that object at index ID
here are the 2 cases which I couldn't handle, because on assign it give an access error
NSMutableDictionary *doctors_set;
for(i=[doctors_sets count]-1;i>=0;i--) {
//this doesn't work
DoctorsSet * set=[doctors_set objectAtIndex:i];
}
i don't want to use for(DoctorsSet *set in doctors_sets)
because i want to pass the array in the reverse order....
If the end goal is to go in reverse use
for (DoctorsSet *set in [doctors_sets reverseObjectEnumerator])

multiple objects for a single index in an NSArray

Is it possible to store multiple objects for a single index in an NSArray?
Sure there are many ways to do this with the most common being to assign a dictionary to each array element
Yes, you probably just want to have an NSArray of NSMutableArrays. You can then call something like this:
[[array objectAtIndex:2] addObject:obj];
or
[[array objectAtIndex:2] objectAtIndex:1];
I'm not sure how dynamic you want the multiple objects to be. How about creating a very simple class with properties of the multiple objects?
I was thinking about a struct but I don't think NSArrays like pointer objects.
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#interface myCompound : NSObject
{
}
#property (nonatomic,strong) NSColor* colour;
#property (nonatomic,strong) NSRegularExpression* expression;
#end
#implementation myCompound
#synthesize colour;
#synthesize expression;
#end
And use this as the element type for NSArray
NSArray<myCompound*>* myArray;