Extending NSMutableData class - iphone

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?

Related

Setting property values programmatically in objective c

I have a file Variables.m for storing properties that I can use in all classes within my app. Now I would like to set a value for one of the properties (say username) in class A and I would like it to be available to all the other classes (B,C,D,E..) in my app like a constant. ie. once they initialize a Variables object (say var) in class B, if they issue var.username, they should get the username that I set in class A.
In effect instead of hardcoding a username value, I want to set it programmatically and have all the classes see the value that I just set. Can I achieve this without passing the Variables object around whenever I navigate to a class?
Alternatively, you can use NSUserDefaults
Set variable in class A:
NSString *usernameToSave = #"John Doe";
[[NSUserDefaults standardUserDefaults] setObject:usernameToSave forKey:#"userName"];
Read variable in any class:
NSString *userName = [[NSUserDefaults standardUserDefaults] objectforKey:#"userName"];
Apart from being simple, this has the advantage (or not) that it's persistent across app restarts.
It has the disadvantage that it's not very secure; for passwords and the like you should use Keychain Services as described here.
Create a singelton class that has the appropriate getters and setters for the items you want it to store.
You can then just reference that single instance from any other class.
For example in your Variables class create a class method like so:
+(Variables*)sharedVariables{
static Variables *myVariables = nil;
if (myVariables != nil){
return myVariables;
}
myVariables = [[Variables alloc]init];
return myVariables;
}
If you want a better implementation then google objective C singleton class implementation.
:)
to use this from your other classed you would just type:
[Variables sharedVariables].whatever
You can use Singleton pattern. Like this.
#interface MySingleton : NSObject
{
NSString *username;
}
#property (nonatomic, retain) NSString *username;
+ (MySingleton *) sharedInstance;
#end
#implementation MySingleton
#synthesyse username;
static MySingleton *sMySingleton = nil;
+ (MySingleton *) sharedInstance
{
#synchronized(self)
{
if (sMySingleton == nil)
{
sMySingleton = [NSAllocateObject([self class], 0, NULL) init];
}
}
return sMySingleton;
}
#end

Protocol types within NSMutableArray

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

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

What is my CoreData fetch request actually returning?

I'm fetching some objects out of a data store but the results aren't what I'm expecting. I'm new to CoreData but I'm fairly certain this should work. What am I missing?
Note that User is a valid managed object and that I include its header file in this code, and that UserID is a valid property of that class.
NSFetchRequest *requestLocal = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"User" inManagedObjectContext:messageManagedObjectContext];
[requestLocal setEntity:entity];
// Set the predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY UserID IN %#", userList];
[requestLocal setPredicate:predicate];
// Set the sorting
... sorting details removed but exist and are fine ...
// Request the data
NSArray *fetchResults = [messageManagedObjectContext executeFetchRequest:requestLocal error:&error];
[requestLocal release];
for (int i; i < [fetchResults count]; i++) {
[fetchResults objectAtIndex:i].UserID = ...<----HERE
}
Isn't fetchResults an array of User objects? Wouldn't [fetchResults objectAtIndex:i] be a User object? Why do I get an error when building that "request for member 'UserID' in something not a structure or union"?
Sorry if this is a basic error, I'm clearly missing some basic concept. I've done a ton of searching and it seems like it should be right. (I also tried fast enumeration but it complained that fetchResults items weren't valid Objective C objects, effectively the same error, I think.)
Update:
(from comment below)
My goal is to update the object, calling saveAction after changing it.
Does the KVC method still refer to the actual object? I tried fast enumeration with:
for (User thisUser in fetchResults) {
... but it didn't like that.
I used the more generic version:
(id thisUser in fetchResults)
...but it won't let me set
[thisUser valueForKey:#"FirstName"] = anything
... insisting that there's no Lvalue.
Will:
[[thisUser valueForKey:#"FirstName"] stringWithString:#"Bob"]
... do the trick or is there a better way? Sorry, I know it's nearly a new question, but I still don't get what is in the fetchResults array.
Your fetchedResults variable contains a NSArray object. However, a NSArray can hold any arbitrary group of objects. Unlike a standard C array, there is no requirement that the NSArray objects all be of a single class.
The dot notation you are using here:
[fetchResults objectAtIndex:i].UserID =
... while a legal syntax, nevertheless confuses the compiler because the compiler has no idea what class of object is returned by [fetchResults objectAtIndex:i]. Without knowing the class it has no idea what the heck UserID is. Hence the error "request for member 'UserID' in something not a structure or union". At the very least you have to cast the return of [fetchResults objectAtIndex:i] to some class so that the complier has a clue as to what 'UserID' is.
However, you simply shouldn't use this construction even though it legal because it is dangerous. See below for the best practice form.
Understanding NSManagedObject and its subclasses can be tricky because NSManagedObject itself uses a trick called associative storage which allows any generic NSManagedObject instances to store any property of any entity defined in any model. This can confuse novices because there are multiple ways to refer to the same entities, instances and properties. Sometimes the examples use generic NSMangedObjects and setValue:forKey:/valueForKey: and other times they use objectInstance.propertyName.
Associative storage works like a dictionary attached to every instance of the NSManagedObject class. When you insert a generic NSManagedObject like this:
NSManagedObject *mo=[NSEntityDescription insertNewObjectForEntityForName:#"User"
inManagedObjectContext:self.managedObjectContext];
... you get an instance of the NSManageObject class whose associative storage keys are set to the properties of the User entity as defined in your data model. You can then set and retrieve the values using key-value coding (which has the same syntax as dictionaries) thusly:
[mo setValue:#"userid0001" forKey:#"UserID"];
NSString *aUserID=[mo valueForKey:#"UserID"];
Associative storage allows you represent any complex data model in code without having to write any custom NSManagedObject subclasses. (In Cocoa, it allows you to use bindings which let you create entire programs without writing any data management code at all.)
However, the generic NSManagedObject class is little better than a glorified dictionary whose saving and reading is handled automatically. If you need data objects with customized behaviors you need to explicitly define a NSManagedObject subclass. If you let Xcode generate the class from the entity in the data model you end up with a source file something like:
User.h
#interface User : NSManagedObject
{
}
#property (nonatomic, retain) NSString * firstName;
#property (nonatomic, retain) NSString * userID;
#property (nonatomic, retain) NSString * lastName;
#end
User.m
#import "User.h"
#implementation User
#dynamic firstName;
#dynamic userID;
#dynamic lastName;
#end
Now, you are no longer limited by to the key-value syntax of associative storage. You can use the dot syntax because the complier has a class to refer to:
User *aUser=[NSEntityDescription insertNewObjectForEntityForName:#"User"
inManagedObjectContext:self.managedObjectContext];
aUser.userID=#"userID0001";
NSString *aUserID=aUser.userID;
With all this in mind, the proper forms of reference to the fetchedResults array become clear. Suppose you want to set all userID properties to a single default value. If you use the generic NSManagedObject class you use:
for (NSManagedObject *aMO in fetchedResults) {
[aMO setValue:#"userid0001" forKey:#"UserID"];
NSString *aUserID=[aMO valueForKey:#"UserID"];
}
If you use a dedicated subclass you would use:
for (User *aUserin fetchedResults) {
aUser.userID=#"userID0001";
NSString *aUserID=aUser.userID;
}
(Note: you can always use the generic form for all NSManagedObject subclasses as well.)
Accessing your CoreData attributes by property Accessors (dot notation) will only work if you have defined a custom NSManagedObject subclass in your Model and defined properties on that class. The implementation should be #dynamic. You'll then have to cast the object to the proper class:
//Assume this exists:
#interface User : NSManagesObject
{
}
#property (nonatomic, retain) NSString* UserID;
#end
#implementation User
#dynamic UserID
#end
// You could do:
for (int i; i < [fetchResults count]; i++) {
((User*)[fetchResults objectAtIndex:i]).UserID = ... // This works
}
Or you may use KVC to access your models properties like this (without needing a class):
for (int i; i < [fetchResults count]; i++) {
[[fetchResults objectAtIndex:i] valueForKey:#"UserID"] = ... // This too
}
You would set the value using [object setValue:newValue forKey:#"UserID"] please note, that newValue needs to be an object in general and one of NSString, NSNumber, NSDate, NSSet for CoreData.
Two additional thoughts:
Your could and should use fast Enumeration on the results array:
for (id object in fetchResults) {
[object valueForKey:#"UserID"] = ...
}
I do not understand the ANY keyword in your predicate. "UserID IN %#" should do as well.
Your basic problem is that -objectAtIndex: returtns an object of type id. No accessors are defined for type id so when you use dot notation with the object returned by -objectAtIndex: the compiler assumes you mean to access a C structure member. id is a pointer type, not a structure type, hence the error you are getting.
The whole core data stuff is a red herring with regard to this issue. You'd get the same error if User was derived from NSObject and you had populated the array yourself manually.
The ways out of it are:
Use fast enumeration
for (User* aUser in theArray)
{
....
}
which is the preferred idiom if you need to iterate through the whole array
Cast the result of -objectAtIndex: to the correct type.
((User*)[theArray objectAtIndex: i]).userId;
Use the message sending syntax instead of dot notation
[[theArray objectAtIndex: i] setUserId: ...];
Personally, I'd go with 1 and 3.
for (User* aUser in theArray)
{
[aUser setUserId: ...]
}
Clearly any of the above are dangerous if you are not certain that the objects in the array are User objects. You can use -respondsToSelector: to make sure it will work if you like.

problem related to NSString

I have 1 NSString *abc = #"Hardik";
i have NSMutableArray *array;
now i had written [array addobject:abc];
then i'm printing,NSLog(#"array = %#", array);
but i'm getting NULL
why?
I have declared NSMutableArray *array; in a.h file
i had set #property(nonatomic,retain)NSMutableArray *array;
#synthesize array;
and i have synthesize it but getting value NULL
I'm not able to understand it?
You also need to initialise your array:
array = [[NSMutableArray alloc] initWithCapacity:10];
This is pretty fundamental stuff. Have you read the "Learning Objective C Primer" yet?
It sounds like you haven't actually allocated array. Generally, you would do this in your initializer. (Don't forget to add a release to your dealloc method, too.) #synthesize creates the getter and setter, but you still have to handle allocating/deallocating the object yourself.
It sounds like your NSMutableArray* array property may not have been initialised?
Can you post your class init method?
To trigger the synthesized accessor within a class itself, you must use self. If you don't, you access the attribute's address directly bypassing the accessor methods. You need:
NSString *abc = #"Hardik";
[self.array addobject:abc];
NSLog(#"array = %#", self.array);
The reason this is important is that the synthesized methods usually also initialize the property. The internals of the synthesize array method would look something like:
-(NSArray *) array{
if (array!=nil) {
return array;
}
array=[[NSMutableArray alloc] initWithCapacity:1];
return array;
}
self.propertyName is really just shorthand for [self propertyName] and self.propertyName=someValue is just shorthand for [self setPropertyName:someValue].
Until you call self.array at least once, the array property is not initialized.
However, just to confuse things, once you have called self.array once it is initialized so you can just call array directly. So...
[self.array addObject:abc];
NSLog(#"array = %#", array);
...works while the converse would return just an empty array.
So the rules are:
Within a class implementation
(including subclasses), calling just
propertyName gives you the address
of the property but does not call
the getter/setter accessor methods.
Within a class implementation
(including subclasses), using
self.propertyName calls the
getter/setter accessor methods but
does not access attribute directly.
From outside the class
implementation e.g.
myClass.propertyName calls the
getter/setter accessor methods.