I have a Core Data model entity NoteObject that has a transformable type arrayOfTags. In the NoteObject.h file, which is a subclass of NSManagedObject, the arrayOfTags is declared as:
NSMutableArray *arrayOfTags;
#property (nonatomic, retain) NSMutableArray *arrayOfTags;
//.m
#dynamic arrayOfTags;
The issue is that changes that are made to this array are not saved. Someone suggested the following as the solution:
If there are mutable and immutable versions of a class you use to
represent a property—such as NSArray and NSMutableArray—you should
typically declare the return value of the get accessor as an immutable
object even if internally the model uses a mutable object.
However I'm not exactly sure what that means. How would I follow those instructions for my case?
Even of you've found a workaround in the meantime try this:
[noteObject willChangeValueForKey:#"arrayOfTags"];
// make changes to noteObject.arrayOfTags
[noteObject didChangeValueForKey:#"arrayOfTags"];
Implementing accessor functions for Core Data varies with your relationship model. This document should help you get started. Most likely you will be using this setup for your getter:
- (NSArray*)data
{
[self willAccessValueForKey:#"data"];
NSArray* array = [[NSArray alloc] initWithArray:arrayOfTags copyItems:YES];
[self didAccessValueForKey:#"data"];
return array;
}
Please note that the above snippet is just an example and will have to be modified for your use.
Related
From documentation, the MKMapView property, Annotations, is a NSArray and not a NSMutableArray. So Annotations is supposed to be "immutable". But MKMapView's instant methods : addAnnotation and removeAnnotation are capable of changing the Annotations array. So on the surface there seems to be some inconsistencies. There must be something I have missed. Hope that somebody knowledgable could shed some light on this.
By declaring the annotations property an NSArray, code that accesses the array through that property cannot safely modify it and must treat it as an immutable NSArray. However, that doesn't mean that the array itself is immutable.
Here's an example of how something like this might work:
#interface MyObject
{
// instance variables
NSMutableArray* internalArrayRepresentation;
}
// properties
#property (nonatomic, readonly) NSArray* immutableAccessor;
// methods
-(void)addItem:(NSObject*)object;
#end
#implementation MyObject
#synthesize immutableAccessor=internalArrayRepresentation;
-(id)init
{
if ((self = [super init]))
{
// create the mutable array
internalArrayRepresentation = [[NSMutableArray alloc] init]
}
}
-(void)addItem:(NSObject*)object
{
[internalArrayRepresentation addObject:object];
}
...
#end
In this example, you can see that internalArrayRepresentation is a mutable array, and that its accessible outside of MyObject as immutableAccessor. But because the property definition says that immutableAccessor is an NSArray, callers need to treat it that way and can't manipulate it.
There are other implementations that can accomplish this as well.
The typical reason to use a pattern like this is because you want MyObject to maintain control over the contents of the array: maybe only certain objects can be added, maybe objects need to be modified or cloned on the way in, maybe anything can be added but nothing can be removed, etc.
You're meant to use addAnnotation and removeAnnotation to add/remove annotations instead of manipulating the annotations array directly.
I assume both those functions do some processing as well as adding/removing annotations from the array.
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.
I am looking for a shorthand way of setting my properties directly to an NSMutableDictionary that is a instance variable. ie:
KVCModle.h:
#interface KVModel : NSObject {
NSMutableDictionary * data;
}
#property(nonatomic,assign)NSString * string1;
#property(nonatomic,assign)NSString * string2;
#end
KVCModel.m
#import "KVModel.h"
#implementation KVModel
-(id)init
{
self = [super init];
if(self)
{
data = [[NSMutableDictionary alloc] init];
}
return self;
}
-(NSString *)string1
{
return [data objectForKey:#"string1"];
}
-(NSString *)string2
{
return [data objectForKey:#"string2"];
}
-(void)setString1:(NSString *)_string1
{
[data setObject:_string1 forKey:#"string1"];
}
-(void)setString2:(NSString *)_string2
{
[data setObject:_string2 forKey:#"string2"];
}
-(void)dealloc
{
[data release];
[super dealloc];
}
#end
I have tried to override setValue:ForKey: and valueForKey:, but those aren't called, they allow you to directly set properties without using the property syntax.
I have made preprocessor macros to make this work in the past, but I am not interested in typing at all, and would like to avoid as much of it as I can in the future. Is there a way to make this work that I am not familiar with?
I have thought about using NSManagedObject, but I am not sure if I can get what I want out of that.
EDIT:
source
If you're trying to access the properties with code like foo = obj.foo and obj.foo = foo, that's why it doesn't work.
Property-access syntax is synonymous with message syntax; the former is exactly the same as foo = [obj foo], and the latter is exactly the same as [obj setFoo:foo]. There is no KVC code to intercept. Properties are at the language level; KVC is at the framework level.
You'll need to intercept the accessor messages instead. Consider implementing the resolveInstanceMethod: class method, in which you “resolve” the selector by adding a method implementation to the class using the Objective-C runtime API. You can add the same implementation(s) for many different selectors.
For your purpose, have a function or method that examines the selector (using NSStringForSelector and regular NSString-examining techniques) and returns two facts: (1) the property name, and (2) whether it's a getter (foo, isFoo) or setter (setFoo:). Then, have two more methods, one a dynamic getter and the other a dynamic setter. When the selector names a getter, add it with your dynamic-getter method; when the selector names a setter, add it with your dynamic-setter method.
So how do the dynamic-getter and -setter methods work? They'll need to know what property to dynamically get and set, but they also need to take no arguments (getter) or one argument (setter, which takes the value), in order to match the original property-access message. You might be wondering how these generic implementations can know what property to get or set. The answer is: It's in the selector! The selector used to send the message is passed to the implementation as the hidden argument _cmd, so examine that selector the same way as before to extract the name of the property you should dynamically get or set. Then, the dynamic getter should send [data objectForKey:keyExtractedFromSelector] and the dynamic setter should send [data setObject:newValue forKey:keyExtractedFromSelector].
Two caveats:
You may still get complaints from the compiler when you use the property-access syntax to access a “property” that you have not declared in the class's #interface. This is normal and intentional; you're really only supposed to use property-access syntax to access known formal properties. What you're doing, while I found it fun to solve, is technically an abuse of the property-access syntax.
This will only work for object values. KVC does the boxing and unboxing for primitive values, such as integers; since KVC is not involved, no free boxing and unboxing. If you have declared formal properties (see 1), you'll need to introspect them using the Objective-C runtime API, and do the boxing and unboxing yourself with your findings.
This piqued my curiosity, so I went ahead and used Peter Hosey's suggestion of overriding +resolveInstanceMethod: to generate the getters and setters. I posted the resulting object (DDDynamicStorageObject) to a github repository:
https://github.com/davedelong/Demos
What you basically want is your own implementation of the NSManagedObject machinery. I have done something similar. Look here: https://gist.github.com/954035 HTH
(Updated the code to remove the dependency on the non-existant NSString+Utilities.h)
(Added missing ReleaseAndZero() macro)
For the love of all that is sacred - do not use an NSDictionary as a place to stuff every conceivable property of a model object. Ivars are easier to debug, and much much clearer to other developers (including your future self).
If you want to use a dictionary, use a dictionary and some statically defined keys - but if you want a model object, use some ivars
I come to the same problem today just like you. So I find your question posted here.
The answers above used the +resolveInstanceMethod: is a little bit hard for me. :)
My understanding is that as long as we setup the property, we would have getter and setter method, so I use the setter method to implement it.
BDLink.h
#property (nonatomic, strong) NSString *type;
#property (nonatomic, strong) NSString *displayName;
#property (nonatomic, strong) NSString *linkURI;
BDLink.m
- (id)initWithLinkInfoDictionary:(NSDictionary *)linkInfoDict {
for (NSString *key in linkInfoDict) {
const char *rawName = [key UTF8String];
NSString *setMethodString = [NSString stringWithFormat:#"set%c%s:", toupper(rawName[0]), (rawName+1)];
SEL setMethod = NSSelectorFromString(setMethodString);
if ([self respondsToSelector:setMethod]) {
[self performSelector:setMethod withObject:linkInfoDict[key]];
}
}
return self;
}
Hope it would be helpful. My first answer, :)
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.
Hey all. I know this sounds simple, but I can't find a way to do it. I have a method in Obj-C that takes in a NSString and then should create a new class with the String as its title.
-(DataModel *)createDataModel:(NSString *)dataModel_name {
DataModel *[initWithString:dataModel_name] = [[DataModel alloc] init];
}
I know I have some problems in this. For starters, I don't know how to define a return on an object whose name could change. Second, I know this doesn't compile considering the initWithString method is wrong. I just don't know what to do or what method to use so that I can create this DataModel object with the specified name...
If your title is setup correctly, as a property:
-(DataModel *)createDataModel:(NSString *)dataModel_name {
DataModel *model = [[DataModel alloc] init];
model.title = dataModel_name;
return model;
}
That would require in your datamodel.h:
#interface DataModel {
NSString *title;
}
#property (nonatomic, retain) NSString *title;
#end
And in your .m:
#implementation DataModel
#synthesize title;
#end
But your question isn't clear if your real purpose is trying to instantiate different classes based on the dataModel_name or if you just have a single generic class with a title that should be set to dataModel_name.
Depending on what you want to do, there are different answers. If you really want different classes based on the name, then you should do things differently. You can use the Cocoa specific type: id, to return any object from a method. Then the method, NSClassFromString() to create the object:
- (id)createDataModel:(NSString *)dataModel_name {
id model = [[NSClassFromString(dataModel_name) alloc] init];
[model setTitle:dataModel_name];
return model;
}
Or you can define a Protocol (Interface in java parlance) that declares the features of your data model. Your method would return that instead.
NSClassFromString() will do what you want. Also, initially declaring variables as type id allows you to set their explicit type later on. So:
id dataModel = [[NSClassFromString(dataModel_name) alloc] init];
To locate or create a new class:
Class arbitraryClass = NSClassFromString(dataModel_name);
if ( nil == arbitraryClass ) arbitraryClass = objc_allocateClassPair( [DataModel class] , [dataModel_name UTF8String] , 0 );
To create a new instance of an object with your newly created class:
DataModel *modelWithArbitratyClassName = [[arbitraryClass alloc] init];
Creating new classes at runtime is not usually a good idea.
So, it seems you want to dynamically add an Instance variable to an object at runtime. You don't get this for free. CALayer and CAAnimation can do something similar to this, you can read about it here
You could add similar functionality to your own objects using Key-value-coding, and more specifically the method valueForUndefinedKey. There will be some KVC specific caveats so you should really make sure you are familiar with and understand KVC. Take a look at this, it might be just want you want.
A dictionary is used to store the value and key, and to retrieve the value when you try to access it.