Adding ivar to an NSManagedObject subclass - iphone

I have a subclass of NSManagedObject Class used with Core Data in iPhone. However, I have a temporary "field" (ivar) that I want to add in that Class (but I dont want to persist it in the data-store). Tried to use informal and formal protocol, but both of them give me a "static-variable" like behaviour. (It behaves like a Class Variable rather than Instance Variable). Any suggestion?
My first attempt, created Test "Dummy-class" which is supposedly a subclass of NSManagedObject, then I created Test-category
#interface Test (custom)
NSString *_string ;
- (void)setString:(NSString *)newString;
- (NSString *)string;
#end
Those are the usual setter and getter. This is the way I use the Test class
Test *a = [[Test alloc] init];
Test *b = [[Test alloc] init];
[a setString:#"Test1"];
NSLog(#"%#", [a string]); //This will print out Test1
[b setString:#"Test2"];
NSLog(#"%#", [b string]); //This will print out Test2
NSLog(#"%#", [a string]); //Unfortunately, this will also print out Test2
I could also mess with the NSManagedObject subclass (which is my Entity) directly but I dont think that is the way to do it.

You can't add an instance variable in the (in)formal protocol or in the category.
Any variable definition inside the category is treated as a variable definition at the file level outside the category, so it behaves like a class variable. It's a confusing behavior; I guess the compiler should warn about it.
The standard solution is to add the ivar which holds transient data (which does not persist in the database) in the subclass representing the entity directly, as in:
#interface MyEntity:NSManagedObject{
NSString*stringHoldingTransientSomething;
}
...
#end
and then specifying MyEntity as the class in the Core Data Editor. Note that Core Data does not automatically save ivars in your custom NSManagedObject subclass; it only saves the properties specified in the Core Data model. So you can add as many book-keeping ivars as you want in your custom subclass.

Related

How to use variables created outside of viewDidLoad

Hey I'm very new to Objective C programming and I'm stuck. How come when I create I function, it can't use the variables I created for the labels or textviews, etc. And whenever I call them in the viewDidLoad function, I have to do either self.(variableName) or _(variableName) and it won't let me do that outside of the viewDidLoad function. Is there a way to access them outside of it?
How come when I create I function, it can't use the variables I
created for the labels or textviews, etc.
For one thing, you need to differentiate between a function and an instance method. In Objective-C, classes can have instance variables (variables that are part of an instance of that class) and instance methods (similar to functions that are associated with an instance of that class). Classes can also have properties, which are used rather like instance variables in that they're values associated with an object, but they're accessed through accessor methods. Functions, on the other hand, aren't part of any class. So, a class has an interface where instance variables and methods are declared, like this:
#interface Person : NSObject
{
NSString *firstName;
NSString *lastName;
}
#property (readonly) NSString *fullName;
#property (strong) NSArray *friends;
#property (assign) int age;
- (id)initWithFirstName:(NSString*)first lastName:(NSString*)last;
- (void)addFriend:(Person*)friend;
#end
And also an implementation, like this:
#implementation Person
- (id)initWithFirstName:(NSString*)first lastName:(NSString*)last
{ /* code goes here */ }
- (void)addFriend:(Person*)friend
{ /* code goes here */ }
- (NSString *)fullName
{ return [NSString stringWithFormat:#"%# %#", firstName, lastName; }
#end
Those things in the implementation are instance methods, as denoted by the - at the beginning and the fact that they're defined in an #implementation block. (If they had + instead of -, they'd be class methods instead of instance methods -- I'll let you read about that in the docs.) Properties are accessed by calling an appropriate accessor methods using either normal method calls or dot notation, so if you have:
Person *george = [[Person alloc] initWithFirstName:#"George" lastName:#"Bailey"]
all of these are valid:
NSString *name1 = george.fullName;
NSString *name2 = [george fullName];
george.age = 45;
[george setAge:45];
int years1 = george.age;
int years2 = [george age];
Also, self is a pointer to "the current object". You can use it in instance methods so that objects can call their own methods and access their own properties. For example, the Person class could contain a method like this:
(NSString *)nameAndAge
{
NSString *nameAndAge = [NSString stringWithFormat:#"%#: %d", self.fullName, self.age];
}
Functions, on the other hand, aren't part of any class, use C function syntax rather than Objective-C method syntax, and aren't defined in an #implementation block:
BOOL isMiddleAged(Person* person)
{
return (person.age > 30) && (person.age < 60);
}
You can't use self in function because a function isn't associated with an object, so there's nothing for self to point to. You can, however, use properties of other objects you know about, such as person.age in the example above.
And whenever I call them in the viewDidLoad function, I have to do
either self.(variableName) or _(variableName) and it won't let me do
that outside of the viewDidLoad function.
You must be accessing properties of your view controller. As explained above, self.(variableName) is the way to access properties. _(variableName) refers to a variable (often generated by the compiler) that stores the value of the property. (You shouldn't normally access those variables directly outside initialization methods and -dealloc -- use the property accessors instead.) You can use those properties in any instance method of the class, not just -viewDidLoad. You can also access properties of other objects by replacing self with the name of a pointer to the object, just as I did with person in isMiddleAged().
Seems like your are using autosythesized property. Using Auto Synthesized property you need not to #syhtesize objects.
#sythesize object = _object; will be implicitly implement in this case.
So you can access object using self.object or _object.
You can #synthesize to avoid using objects via self.varName or _varName .You can directly use it using varName.

creating an object out of multiple variable types

I have an NSDictionary that I am passing to a NSObject Class where I pull all of the values out of the dictionary and pass them into their correct types.
For instance NSInteger, BOOL, NSString, char are the types of values I am pulling out of the NSDictionary and putting into their only variables.
My question what is the best way to turn these values into one big object that can then be putt into an array?
I have heard that I can use the class itself as an Object.. But I am not really sure how to do this.
or could I just put them back into a NSDictionary?... but if thats the case do NSDictionaries allow for multiple value types?
Actually, you are in the right path. this is basically MVC architecture way. so you are questioning about M = Model.
Model in here example is class that defines all variables. cut to the point, here's you should do:
-> create a class that contain your variable, with #property & #synthesize name : ClassA.
then you could set object ClassA into dictionary.
ClassA *myClass = [[ClassA alloc] init];
myClass.myString = #"test String";
myClass.myBoolean = True;
[dictionary setObject:myClass forKey:#"myObject"];
[myClass release]; //we no longer need the object because already retain in dictionary.
then retrieve it by :
ClassA *myClass = (ClassA*)[dictionary objectForKey:#"myObject"];
NSLog(#"this is value of myString : %# & boolean : %i",myClass.myString,myClass.myBoolean);
You can put the collection of values in NSDictionary, NSArray, NSMutableArray, etc. Any of the collection types. Or if you have a fixed number of values/types, you can create a class that has a data member for each value/type and put it in that. The class solution would eliminate having to do a lot of casting, but it also only works if there are a fixed number of values/types.
Here is the AppleDoc on collections.
Yeah, You can create a class itself with these as different values as a properties.Once you pass this object to any class you can access those values there by obj.propertyName.Doing by this Lead to create Modal in MVC pattern.
Please let me know if there is doubt.
Test *object = [[Test alloc] init];
object.testBool=true;
object.testString=#"Test";
NSDictionary *passData = [[NSDictionary alloc] initWithObjectsAndKeys:object,#"testObject", nil];
Test *getObject = (Test*)[passData objectForKey:#"testObject"];
NSLog(#"%d",getObject.testBool);
NSLog(#"%#",getObject.testString);
You can customized the init method of Test Class.

How can i lazy initialize a NSMutableArray?

How can i lazily initialize a NSMutableArray of Buttons ? I do something like this :
-(NSMutableArray *)roasteryButtons
{
if(!roasteryButtons)
{
roasteryButtons = [ NSMutableArray new];
//other code
}
return roasteryButtons;
}
And don't know what to do to call this lazy initializer ? i.e. I need to initialize the array so that i may set the frame for every button in the array
What u have done is correct. Instead of allocating the array in the init method of class, u are allocating the array only when required. Thus it serves the purpose of lazily allocating.
In the class, Wherever you want the array, you just call,
NSMutableArray *arr = [self roasteryButtons];
Also declare the method in header file as, -(NSMutableArray*)roasteryButtons;.
If you want the reference of the array in other classes, the call like,
[classObj roasteryButtons];
I have shown it as instance method. You can also declare that as class method, if you want like that.
And release that in -(void)dealloc method.
I guess you know when to call this method, right ?
The first thing is that you shouldn't use "new" method, but [[NSMutableArray alloc] init] instead : You should have a look at all existing [Init] methods available for NSArray : there are a bunch of them (with capacity, with objects, etc...)
Anyway, you should add some parameters to your method [roasteryButtons] : parameters that will help the method to know, for instance how many buttons to create, what is the frame where they have to show, etc. So this will look a bit like
-(NSMutableArray *)roasteryButtonsWithFrame:(*Frame) andNumbersOfButtons:(int)
for example...
or instead of parameters, you can pass a reference to a delegate that will be able to give answers to those questions (How many buttons, what's my frame and bounds, etc.) So in this case, the method will look like :
-(NSMutableArray *)roasteryButtonsWithDelegate:(id)
(This delegate should implement a protocol that you will create, containing the different methods that the delegate will have to respond to. ie methods like [howManyButtons]...)
The Perfect Way to Lazy initialize is as follow
in .h file declare your NSMUtableArray as property as follow
#property (nonatomic,strong) NSMutableArray *array;
Now in .m file synthesize it and do lazy initialize in getter like as follow:
#synthesize array=_array;
(NSMutableArray *) array
{
(!_array) _array=[[NSMutableArray alloc]init];
//this line is called lazy intialization..this line will create MutableArray at program //run time.
return _array
}
Now answer why we need this is that it take care about that if no NSMutableArray is created then it create it at programme run time and like this your app will not crash.
You could make your method a class method:
+(NSMutableArray *)roasteryButtons {
in this way you will be able to call it like this:
[MyRoasteryButtonClass roasteryButtons];
and this will return you your object.
Hope this helps.

Trouble Copying custom class initialization

I have a custom class of type NSObject that contains a single NSMutableArray. This class is called Mutable2DArray and is designed to emulate a 2 dimensional array of type NSMutableArray. There is a custom init method - (id)initWithX:(int)x Y:(int)y that asks for the dimensions for the array and allocates the required arrays within the only array the class owns.
My issue is when I try to copy an instance of Mutable2DArray I get an error saying the copyWithZone is an unrecognized selector. I thought copy was a base method of NSObject so I'm confused why I cant create a copy of the instance like this:
Mutable2DArray *Array1 = [[Mutable2DArray alloc] initWithX:10 Y:10];
Mutable2DArray *Array2 = [Array1 copy];
Am I missing something so obvious here?
Things that I can think of to check, off the top of my head:
Does the header file actually declare the interface as inheriting from NSObject?
Does your custom initWithX: Y: method call [super init] before finishing?

Adding a decorator to a class derived from NSManagedObject

I'd like to add additional behavior to a class derives from NSManagedObject and there are 4 distinct (for now) groups of behaviors. I don't need my decorator class to be persisted with CoreData -- it's purely for adding run-time behavior.
However, if I try to apply the standard Decorator pattern, I can't call '[super init]', which makes sense because you need to insert the new object into the ManageObjectContext. But I thought you'd want to invoke [super init] within WindowClassScrollDecorator's init and likewise, later 'dealloc' so everything gets initialized & cleaned up correctly.
I'm inheriting from 'MyWindowClass' class because I don't want my client classes to know the subtype but depending on the decorator used, the behavior will be different.
So what's a good way to approach this?
#interface MyWindowClass : NSManagedObject
{
}
#end
#interface WindowClassScrollDecorator: MyWindowClass
{
MyWindowClass *decoratedClass;
}
- (id)initWithMyWindowClass:(MyWindowClass *)aWindowClass;
#end
#implementation WindowClassScrollDecorator
- (id)initWithMyWindowClass:(MyWindowClass *)aWindowClass
{
// Calling [super init] elicits the following error:
// Failed to call designated initializer on NSManagedObject class 'ModelClassScrollDecorator'
if (self = [super init])
{
// do some initialization work here
self.decoratedClass = aWindowClass;
}
}
#end
The lifecycle of NSManagedObjects is a bit different from that of other objects; specifically, the object may turn into a fault (essentially a shell object without any of its properties set) without being deallocated. You should be sure to be aware of these events, so you may want to look at the NSManagedObject Class Reference - Subclassing Notes document. Specifically, you may want to look into awakeFromInsert:, awakeFromFetch:, and (will|did)TurnIntoFault.
To address your immediate issue, an NSManagedObject cannot be created without an NSManagedObjectContext to live in. Thus, to initialize a managed object, you must call its designated initializer:
initWithEntity:insertIntoManagedObjectContext:
Your init method needs to call that method on the superclass or else your NSManagedObject won't work.
The question you have here seems to not be CoreData specific but OO design.
You shouldn't be inheriting NSManagedObject if it is not a NSManagedObject.
You should make MyWindowClass either be a protocol, or a class which has a NSManagedObject.