Protocol types within NSMutableArray - iphone

I am trying to introduce some generics-style approaches from .NET into my iOS development. I am retrieving a list of custom objects of type Example.
I have defined a protocol that Example class implements:
#protocol ExampleProtocol
#property(nonatomic,assign) int Id;
#property(nonatomic,copy)NSString *Description;
#optional
#property(nonatomic,copy)NSString *Icon;
#end
I then retrieve my NSMutableArray of Example as follows:
id<ExampleProtocol> anExample = [arrayOfExampleProtocols objectAtIndex:0];
The problem I have is that anExample is always empty regardless of the contents of the NSMutableArray. My ultimate aim is to be able to reference the properties with the following syntax:
id<ExampleProtocol> anExample = [arrayOfExampleProtocols objectAtIndex:0];
NSString *test = [anExample Description];

There are no generics in Obj-C. The "protocol" is a messaging mechanism. Please see this post: No Generics in Obj-C

Related

Extending NSMutableData class

My question is simple. I want to extend the NSMutableData class in iOS and override some of the methods defined in NSMutableData. For e.g. I want to override writeToFile function with my own wrapper implementation for it.
Is it possible to do this?
My TestNSMutableData.h
#interface TestNSMutableData : NSMutableData
-(BOOL)writeToFile:(NSString*)path atomically:(BOOL)useAuxiliaryFile;
#end
My TestNSMutableData.m
#implementation TestNSMutableData
-(BOOL)writeToFile:(NSString*)path atomically:(BOOL)useAuxiliaryFile{
//Some activity on the data and modifying it
return [self writeToFile:path atomically:useAuxiliaryFile];
}
When I try to use the TestNSMutableData in one of my project like
TestNSMutableData myData;
myData = [TestNSMutableData alloc]init];
[myData writeToFile:path atomically:YES]
I get an error as follows
NSInvalidArgumentException'- reason '* - length only defined for abstract class. Define -[TestNSMutableData length] !
Is it possible at all to override the methods defined in Native classed for e.g. NSMutableData ?
UPDATE
I create NSString class category method for writeTofile
My implementation is
-(BOOL)writeToFile:(NSString*)path atomically:(BOOL)useAuxiliary encoding:(NSStringEncoding)enc error:(NSError**)error{
//Manipulating NSString
self = manipulatedString;
return [super writeToFile....];
}
I get a warning "NSObject may not respond to 'writeToFile' function. Which is technically correct as NSString is derived from NSObject and NSObject does not have writeToFile function.
What I want is to write the manipulated string in the file and not the actual string.
Is there a way to call the NSString writeToFile method from the above function.
Regards,
Nirav
NSMutableData is probably a class cluster, making it a bit hard to subclass. Why not use a category to add a custom -writeToFile method instead?

JSON Dictionary to Core Data

I have a JSON response that I turn into a Dictionary like so:
NSError *error;
self.restKitResponseDict = [NSDictionary dictionaryWithDictionary:[NSJSONSerialization JSONObjectWithData:response.body options:0 error:&error]];
I have a core data class that has the following attributes/properties:
name
image_url
When I log the restKitResponseDict from above I see that image_url is listed as "image_url" like this:
name = Rock;
"image_url" = "http://f.cl.ly/items/122s3f1M1E1p432B211Q/catstronaut.jpg";
Is this why KVC is crashing on
[CoreDataClass setValuesForKeysWithDictionary:self.restKitResponseDict];
like this:
'[<CoreDataClass 0x14132c> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key image_url.'
Do the quotes matter? Should I ask my server guy to get rid of the underscore that's likely causing it?
Core Data Class:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataClass : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * image_url;
#end
#implementation CoreDataClass
#dynamic name;
#dynamic image_url;
#end
You are sending the method to the class object:
[CoreDataClass setValuesForKeysWithDictionary:self.restKitResponseDict];
when you probably want to send it to the actual CoreDataClass instance:
[coreDataClassObject setValuesForKeysWithDictionary:self.restKitResponseDict];
EDIT
what's the simplest way to init the object from the class? – Eric
It's a subclass of NSManagedObject, so you use the normal Core Data methods. One way to create a new object:
CoreDataClass *coreDataObject = [NSEntityDescription
insertNewObjectForEntityForName:#"YOUR_ENTITY_NAME"
inManagedObjectContext:managedObjectContext];
If you need basic information about using Core Data, see the Core Data Programming Guide: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/coredata/cdProgrammingGuide.html#//apple_ref/doc/uid/TP30001200-SW1
The NSLog() with the %# format uses the description method to print objects, and the description of a NSDictionary puts quotation marks around all keys and values that contain any special characters, such as the underscore. For example
NSDictionary *dict = #{
#"key1" : #"value_1",
#"key_2" : #"value2"
};
NSLog(#"dict=%#", dict);
produces
2012-08-25 18:15:33.553 test27[3416:c07] dict={
key1 = "value_1";
"key_2" = value2;
}
Therefore the key in your JSON dictionary does not really have quotation marks, and the underscore is probably not the cause of the error.
The error message indicates that the managed object does not have an image_url attribute, therefore you should check that.

Create NSDictionary-backed objects

I want to create a "business object" based on a NSDictionary. The reason for this is that I want implementations to be able to extend this object with arbitrary keys, and another reason is that I am persisting it using the convenient plist format (the objects stored are either integers, floats or strings).
The business object contains a number of predefined properties, e.g.
#property NSString* customerName;
#property NSString* productCode;
#property int count;
#property double unitPrice;
I want to serialize this, for example to a property list (this is not a strict requirement, it could be some other easy-to-use format). Preferably, the implementation of the class should be just
#synthesize customerName, productCode, count, unitPrice:
for the example above. To use this class, I want to do something like:
MyBusinessObject* obj = [MyBusinessObject businessObjectWithContentsOfFile:fileName];
obj.productCode = #"Example";
[obj setObject:#"Some data" forKey:#"AnExtendedProperty"];
[obj writeToFile:fileName atomically:YES];
You should make your class KVC complaint. KVC does the magic. Look here.Ex,
// assume inputValues contains values we want to
// set on the person
NSDictionary * inputValues;
YOURCLASS * person = [[YOURCLASS alloc] init];
[person setValuesForKeysWithDictionary: inputValues];
The "path of least resistance" turned out to be using NSCoding instead.

can't copy NSString object to my custom object's property Objective-c

How to copy NSString data to my custom object's NSString property?
I have an object question with NSString *text and KDoctor *doctor properties.
KDoctor is an object with two properties: NSString *name and UIImage *photo.
self.question.doctor.name=#"abc";
NSLog(#"doctorname: %#", question.doctor.name);
Output is:
doctorname: (null)
Why? How could I solve this problem?
my guess is that question.doctor != self.question.doctor
or
question == nil
or
question.doctor == nil
It seems you have something wrong declaring the properly. Are you defining "question" property like this?
In your header:
#class KonsQuestion
#interface YourClass : NSObject {
KonsQuestion * _question;
}
#property(nonatomic, retain) KonsQuestion * question;
In the implementation file:
#implementation YourClass
#synthesize question = _question
#end
In this case you should use always self.question to use the getter and setters generated and use [_question release] in the dealloc method

NSInteger,NSNumber "property 'x' with 'retain' attribute must be of object type "

I am working an application in which data is being populated from an sqlite database. All database related stuff is done in the appdelegate class. I have used NSMutable array to hold objects.
I have used a separate NSObject class for properties.
I am getting the error: property 'x' with 'retain' attribute must be of object type.
My appdelegate.m file's code is as:
NSString *amovieName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
NSInteger amovieId = sqlite3_column_int(compiledStatement, 1);
//problem is here the
//value of movieId is coming from database.
//But error: "must be of object type" is puzzling me.
//I am assuming to use NSNumber here.
my NSObject file's code is as:
in .h file-
NSInteger movieId;
its property as:
#property (nonatomic, retain) NSInteger movieId;
and in .m file-
#synthesize movieId;
then I have just initialize as:
-(id)initWithmovieName:(NSString *)mN movieId:(NSInteger)mId
{
self.movieName=mN;
self.movieId=mId;
return self;
}
I found another way as:
assigning value in a NSnumber object .then type caste in NSInteger.for ex;
NSNumber aNSNumbermovieID = sqlite3_column_int(compiledStatement, 1);
NSInteger amovieId = [aNSNumbermovieID integerValue];
but still I am getting the same errors(property 'x' with 'retain' attribute must be of object type).
Any suggestion?
NSInteger is a scalar and not an object. So you shouldn't retain it, it should be assigned. Changing your property will clear up the warning message. You don't need to do the NSNumber stuff that you added in.
#property (nonatomic, assign) NSInteger movieId;
It's a little confusing since NSInteger sounds like a class, but it's just a typedef for int. Apple introduced it as part of 64-bit support so that they can typedef it to the appropriately sized integer for the processor the code is being compiled for.
Just use NSNumber and you can do:
#property (nonatomic, retain) NSNumber *movieId;
I think the error is because of the #property retain for NSInteger. Assign is for primitive values like BOOL, NSInteger or double. For objects use retain or copy, depending on if you want to keep a reference to the original object or make a copy of it.
Here NSInteger is clearly not an object so you should try assign instead of retain