Objective C initialization of a derived NSObject and further assignation - objective-c

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])

Related

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

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];

Traversing a NSMutableArray?

To start let me tell you I am a total Objective-C beginner. This is my problem:
I have a NSMutableArray that stores objects, (Player) that has the name of the player and his/her score.
I am able to add objects to the array using addObject, but I am having trouble traversing this array. This
is how I do it:
// Get the reference to the array
NSMutableArray *myarray = [delegate getArray];
// Create a numerator
NSEnumerator *e = [myarray objectEnumerator];
id object;
while (object = [e nextObject])
{
[object printPlayer];
}
The method printPlayer belongs to the Player class and it just prints the name and the score.
The problem is when I have three players in the array and I am trying to print the content, it reaches this error inside the printPlayer method:
Thread 1: EXC_BAD_ACCESS(code=1, address=0x0000008)
Strangely if I use NSLog(#"%#", object); instead of [object printPlayer]; it prints a reference to the object and does not reach any error.
Anyone could point me what could be the problem when I try to use [object printPlayer]
Cheers
Update 1:
This is my printPlayer method:
-(void) printPlayer
{
NSLog(#"\n\nName: %#\nScore: %d", playerName, playerScore);
}
Update 2:
Player.h:
#interface PROGPlayer : NSObject
#property (nonatomic, assign) NSString *playerName;
#property (nonatomic, assign) int playerScore;
-(id) init: (NSString *) n;
-(void) printPlayer;
#end
Player.m:
#import "PROGPlayer.h"
#implementation PROGPlayer
#synthesize playerName;
#synthesize playerScore;
/**
* Player's class constructor
* #param n Player's name
* #param s Player's score
*/
-init: (NSString *) n
{
if (!(self = [super init])) return nil;
else
{
playerName = n;
playerScore = 0;
}
return self;
}
-(void) printPlayer
{
NSLog(#"\n\nName: %#\nScore: %d", playerName, playerScore);
}
#end
It seems like your problem is in the way you're defining your properties.
You're using assign rather than strong, or copy.
In a nutshell, it's because strong implies that you want your object to be retained.
Using copy implies that you want to create a new copy of an object or a value and set that as value of your property... As Mario and Jarsen explain, using copy is better practice when working with arrays to prevent the array being mutated (i.e. values changed) while it is being enumerated / traversed. Using copy also retains the new object.
If you're using ARC and your objects are not retained, then they will be released automatically by the compiler.
Using assign means that you assume the new object has been retained elsewhere and that you don't want to retain it again.
I suppose what was happening is that you were assigning your variable to your property, but the variable was being released (and hence resulting in nil) and causing the crash.
Here are a few links:
New to Objective C: Need help understanding strong reference vs assign
Objective-C ARC: strong vs retain and weak vs assign
Clarification on assign, retain, copy, strong?
Your playerName property should best be copied instead of assigned
#property (nonatomic, copy) NSString *playerName;
When trying to access the assigned value, the object most likely is gone causing the bad access.
Also remember to release playerName in dealloc when you set the property to copy.
Cheers
You just want to enumerate the array?
for (CustomClass *object in myArray){
[object printPlayer];
}
Either what Mike Z said or the "crude":
for (int i = 0; i < myArray.count; i++) {
CustomClass* object = [myArray objectAtIndex:i];
[object printPlayer];
}
While there are more elegant schemes, you can clearly understand what this one is doing, and how an NS(Mutable)Array is just a simple analog to a standard C array.

Objective C - respondsToSelector for dynamic properties

I am currently facing the problem to check whether a property of an Object (NSManagedObject) exists or not.
Unfortunately the method
[[MyObject class] respondsToSelector:#selector(myProperty)];
always returns NO.
I think it's because the property generated by CoreData is a new style property ala
#property (nonatomic, strong) NSString *myProperty
So any ideas how to solve this issue?
I would really appreciate all of your suggestions ;)
Thanks in advance!
Alex
[[MyObject class] respondsToSelector:...] asks whether the metaobject responds to that selector. So, in effect, it asks whether there is a class method with that selector. Your code would return YES if you had:
+ (NSString *)myProperty;
It returns NO because you have the equivalent of the instance method:
- (NSString *)myProperty;
You need to call respondsToSelector: on an instance of your class.
You could normally use instancesRespondToSelector: directly on the metaclass (so, [MyObject instancesRespondToSelector:...]) but Core Data synthesises the relevant method implementations only when you create an object, so that's a non-starter. You could however create an instance via the normal NSEntityDescription route and test respondsToSelector: on that.
Since it's all Core Data, an alternative would be to ask the NSManagedObjectModel for the relevant NSEntityDescription via its entitiesByName dictionary and inspect the entity description's propertiesByName dictionary.
The only cases I've required this has been to set things dynamically so I am only looking for the setter. I am just composing the signature for the setter and then testing that it exists and then using it.
NSArray * keys = [myObject allKeys];
for(NSString * key in keys)
{
NSString * string = [NSString stringWithFormat:#"set%#:", [key capitalizedString]];
SEL selector = NSSelectorFromString(string);
if([myObject respondsToSelector:selector] == YES)
{
id object = [dict objectForKey:key];
// To massage the compiler's warnings avoid performSelector
IMP imp = [card methodForSelector:selector];
void (*method)(id, SEL, id) = (void *)imp;
method(myObject, selector, object);
}
}
This code satisfies a need where you may not be digesting all the data you receive in the dictionary.
In this case it was sparse json, so some data may not always exist in the json so stepping thru myObjects attributes looking for their corresponding key would just be a lot of wasted effort.
Are you synthesizing the property in the class file?
#interface SomeClass : NSObject
{
#property (nonatomic, strong) NSString *myProperty
}
#end
#implementation SomeClass
#synthesize myProperty;
#end

interesting task for Fast enumeration protocol

How is known to support FE protocol, I must implement method:
– countByEnumeratingWithState:objects:count:
But it method is do not knows what type of object I want enumerate. For example my custom object has two arrays:
NSArray* names - for NSString objects;
NSArray* sites - for NSURL objects;
Now I want enumerate them:
for( NSString* name in myObj )
{
}
and
for( NSURL* url in myObj )
{
}
Can I do that – countByEnumeratingWithState:objects:count: define what kind of objects it must enumerate? (Without using additional class attributes :) )
No. Fast enumeration can only support one type of enumeration per class so you would have to decide which case is more important for you.
However, NSEnumerator also supports fast enumeration. So your class could support 2 different enumerators (let's call them nameEnumerator and urlEnumerator) and the class's users can then use fast enumeration like this:
for (NSString *name in [myObj nameEnumerator]) { ... }
for (NSURL *url in [myObj urlEnumerator]) { ... }
No, type information is not available in that way. I can't think of any mainstream language that would allow return type polymorphism in this way, which is what you're asking for.
Why not simply expose the arrays as properties?
#interface myObj {
NSArray *names;
NSArray *sites;
}
#property(readonly) NSArray *names;
#property(readonly) NSArray *sites;
#end
#implementation myObj
#synthesize names, sites;
#end
Then you can do this:
for (NSString* name in myObj.names) {
}
for (NSURL* sites in myObj.sites) {
}
Yes, you can do that as long as you ensure that only NSStrings are in names and only NSURLs in sites. You only make a cast with "NSString*" telling the compiler that you know that names contains NSString objects. You don't actually enforce that these are only NSString objects. Hope that helped.
for( NSString* name in [myObj names] ) {…}
and
for( NSURL* url in [myObj sites] ) {…}

Objective C - How to add a method to an existing class?

How can i add a new method to NSString class.
I need to create a method that get's called on a string and returns an NSDictionary.
I know that i can simply create a function that gets a string and return an nsdictionary, but i want to know how to add it to an existing class.
NSString *myStr = #"some json string";
NSDictionary *dictionary = [myStr getJSONData];
You can use Objective-C categories. For example to add on to NSString define the following in a new .h/.m file:
#interface NSString (CategoryName)
-(NSString *) aNewMethod;
#end