KVO or custom accessor methods? - ios

I got few entities for an iOS App which are linked by relations. To make a simple example, lets assume we got a relation like this (one-to-many):
company <--->> person
I'm using xcode 4.6 and the core data modelling tool for model generation, so I end up with
//Company.h
#class Person;
#interface Company : NSManagedObject
#property (nonatomic, retain) NSString * company_name;
#property (nonatomic, retain) NSNumber *has_changed;
#property (nonatomic, retain) NSSet *person;
#end
#interface Company (CoreDataGeneratedAccessors)
- (void)addPersonObject:(Person *)value;
- (void)removePersonObject:(Person *)value;
- (void)addPerson:(NSSet *)values;
- (void)removePerson:(NSSet *)values;
#end
//Company.m
#import "Company.h"
#import "Person.h"
#implementation Company
#dynamic company_name;
#dynamic has_changed;
#dynamic person;
#end
And
//Person.h
#class Company;
#interface Person : NSManagedObject
#property (nonatomic, retain) NSString * first_name;
#property (nonatomic, retain) NSString * last_name;
#property (nonatomic, retain) Company *company;
#end
//Person.m
#import "Person.h"
#import "Company.h"
#implementation Person
#dynamic first_name;
#dynamic last_name;
#dynamic company;
#end
Now, suppose I want to set the boolean (implemented as NSNumber in Core Data) attribute has_changed to TRUE every time one of the following occurs:
a attribute of the company entity is changed, except the has_changed attribute itself of course (since this would cause a loop)
a attribute of the person entity is changed
What would be the best (easy to implement + fast to process) way to implement something like this? For what I was able to find out, is that there are two options:
Key value observing (KVO)
custom method accessors
However, everything I find related to this topic seems to be outdated because of the changes in objective-c 2.0, core-data / cocoa or iOS. For example, automatically generating the accessor methods by using the core-data modelling editor dosn't seem to work when using xcode 4.6 with ARC enabled, since everything I get pasted are the #dynamic lines which core-data generates anyways (see code example above).
Also I find it a bit confusing what the documentation says. What would be the best way to implement this? KVO? Custom accessors? Bit of both or even something compleatly different? And how would a possible implementation look like for the given example?

You could do this as such:
#implementation Company
// ...
- (void) didChangeValueForKey: (NSString *) key
{
[super didChangeValueForKey: key];
if (! [key isEqualToString: #"has_changed"])
self.has_changed = YES;
}
// ...
#end
and similar for Person though the company property. You'd also want to implement didChangeValueForKey:withSetMutation:usingObjects:
Note that this suggestion does not address the common need of having a controller know about a change. There are other ways to do that.

Related

Abstract Factory method pattern

I have gone through couple of video and blog tuts online. Felt like i understood everything, however still struggling to implement the Abstract factory pattern. Here is my requirement:
I have a User class which should give a user object.
There are two types of users in my application for e.g Service Provider (Provider) and Service receiver (Consumer).
There are some common properties between these two types of users like name, email id , mobile number etc. For Provider type there will be some extra properties.
Provider types could be of for e.g. TaxiDriver or Restaurant etc.
I want to implement Abstract factory and factory method pattern for this user class so that the application can be decoupled from the User model and whenever the application wants an User of type Provider or Consumer it should get the right object.
What I tried so far:
AbstracUserProtocol.h
#protocol AbstractUserProtocol
#required
#property(nonatomic, strong) id delegate;
#property(nonatomic, readonly, getter=isExist) BOOL exist;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailID;
#property (nonatomic, assign) NSInteger phoneNumber;
-(void)saveUserData;
-(void)retrievUserData;
#end
AbstractUser.h
#interface AbstractUser : NSObject <AbstractUserProtocol>
-(id)initWithType:(UserType)usrType;
#end
AbstractUser.m
#implementation AbstractUser
#synthesize delegate, exist, name, emailID, phoneNumber;
-(id)initWithType:(UserType)usrType
{
self = nil;
if (usrType == kConsumer) {
self = [Consumer alloc]init];
}
else if (usrType == kProvider) {
self = [ProviderFactory alloc] initWithServiceType:TaxiService];
}
return self;
}
-(void)saveUserData {
[NSException raise:NSInternalInconsistencyException
format:#"You have not implemented %# in %#",
NSStringFromSelector(_cmd), NSStringFromClass([self class])];
}
-(void)retrievUserData {
}
#end
Now created two subclasses Consumer and ProviderFactory from AbstractUser class.
Consumer.h
#interface Consumer : AbstractUser
#property (nonatomic, strong) NSString *address;
#end
ProviderFactory.h
#interface ProviderFactory : AbstractUser
-(id)initWithServiceType:(ServiceType)srvType;
#property(nonatomic, strong) NSString *ownerDetails;
#end
So whenever in future if my application want to support another business user like Taxi and Restaurant type then I just have to create a class and init through ProviderFactory class.
Is my approach correct for the abstract Factory pattern? Appreciate any guidance.
Based on your follow up question, I edited the answer.
I'm not entirely sure you need to use AbstractFactory for what you are trying to accomplish. The basics of AbstractFactory is that it allows you to
provide an interface for creating families of related or dependent
objects without specifying their concrete classes (Gamma et al.)
Take this example from Design Patterns: Elements of Reusable Object-Oriented Software by Gamma et al. Let's say you are creating a toolkit to build user interfaces for a document editor. You may have a bunch of widget objects like scrollers, buttons, toolbars, etc. But you may want to later add a different look-and-feel to the document editor. So then you can use AbstractFactory to provide an interface to create all of the widget products (i.e. createScrollbar, createButtons, etc.) but then to change the look-and-feel, you subclass the abstract class and override the methods so that say, createScrollbar returns a scrollbar that has a 3-D effect. In another case, you subclass the abstract class to create a pink scrollbar. The options are endless, and since your client code doesn't care what the scrollbar looks like (all the client cares about is whether it scrolls text or not), you can easily add future looks-and-feels without touching the client code.
In your case, the client cares what kind of AbstractUser it is getting because in some cases it needs a Customer and in some cases a Provider. So either way, your client code would have to be changed if in the future you added a new kind of user.
That said, I think the best approach for you would be to just create an abstract base class of User and then subclass it and add the user-specific properties to the subclass. Here is an example of what I mean.
AbstractUser.h
#import <Foundation/Foundation.h>
#interface AbstractUser : NSObject
#property(nonatomic, strong) id delegate;
#property(nonatomic, readonly, getter=isExist) BOOL exist;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailID;
#property (nonatomic, assign) NSInteger phoneNumber;
#end
Consumer.h
#import "AbstractUser.h"
#interface Consumer : AbstractUser
#property (strong, nonatomic) NSString *address;
#end
ViewController.m
#import "ViewController.h"
#import "Consumer.h"
#import "Provider.h"
#interface ViewController ()
#property (strong, nonatomic) Consumer *consumer;
#property (strong, nonatomic) Provider *provider;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_consumer = [[Consumer alloc] init];
_provider = [[Provider alloc] init];
self.consumer.name = #"Jason";
self.consumer.address = #"some address";
self.provider.name = #"Stack Overflow";
#end

ios/objective-c/core-data: How to show relationship as property in NSManagedObjects

I have two entities and have just created a 1:1 relationship between them. There are subclasses for the entities but they have a lot of code in them at this point so I don't want to use Xcode to automatically generate new NSManagedObject subclasses.
Instead, I thought I could just reference the relationship with a property in each one. I did that and it seemed to work for a while but now it is throwing mysterious errors and I can't seem to get rid of them. I have imported the reciprocal of each one but it is not helping. Can anyone recommend what I should do? Many thanks in advance.
Subclassed NSManagedObjects (simplified)
//Items.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Notes.h"
#interface Items : NSManagedObject
#property (nonatomic, retain) NSNumber *iid;
#property (nonatomic, retain) NSString *item;
//this is relationship
#property (nonatomic, retain) Notes *note;
//above throws error Unkown Type Name 'Notes'
#end
//Notes.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Items.h"
#interface Notes : NSManagedObject
#property (nonatomic, retain) NSNumber * nid;
#property (nonatomic, retain) NSString * note;
//this is relationship
#property (nonatomic, retain) Items *item;
//above throws error Unkown Type Name 'Item'
#end
This is similar to relationship
In Objective-C you can't use a type before it is declared. To fix this you can use a forward declaration of your classes by putting these lines below the #import statements and above the first #interface.
#class Items;
#class Notes;
If your posted code is not representative of your actual file structure (which I assume it isn't), you'll have to put the #class statement for Items in the Notes.h file and the #class statement for Notes in the Items.h file.

objective-C how to declare private property for category?

I'm new to objective-C, so apologies if this is repeated somewhere. I have a category(?) that is something like:
inside SomeClass.h:
#interface SomeClass (SomeCategory) <SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#property (nonatomic, retain) id someProperty; // <-- i want to move this to "private"
#end
and now in my SomeClass.m, all i have is:
#implementation SomeClass (SomeCategory)
// dynamic setters/getters here for someProperty.
#end
I think the someProperty is public. how do i make this "private"? (in other words, how do i syntactically put this in the .m file? i tried to use
#interface SomeClass (SomeCategory) {
#property (nonatomic, retain) somePrivateProperty;
}
#end
but it just complains that i have duplicate definition of the category. how do i do this correctly?
In your .h file, you should not give the category. Just use:
#interface SomeClass : SomeBaseClass < SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#end
In your .m file, define your private property inside a class extension:
#interface SomeClass ()
#property (nonatomic, retain) id somePrivateProperty;
#end
A class extension is not a like category in that it allows you to extend an interface as well as add new storage to your class.
In a class category, you can define new properties, but no storage will be allocated for it, so you have to do it by hand:
#interface SomeClass (SomeBaseCategory)
#property (nonatomic, retain) id somePrivateProperty;
#end
#implementation SomeClass {
id _somePrivateProperty;
}
- (void)setSomePrivateProperty:(id)property {
_somePrivateProperty = property;
}
- (id)somePrivateProperty {
return _somePrivateProperty;
}
#end
Otherwise your app will crash.
In any case, keep in mind that given the dynamic nature of Objective-C, your property will never be fully private, since you can always send a message to an Objective-C object through objc_msgsend and thus set or read the property value.
EDIT:
If you do not have the source code for a class implementation, you cannot define a class extension (as per source linked above).
In this case, you could use object association to define properties.
Just add the category definition in the .m file OUTSIDE the implementation block
Like so:
#interface MyClass (MyCategory)
#property (assign) BOOL myPrivateProperty;
#end
#implementation MyClass
...
#end
Categories are best used for adding capability to code you do not own and cannot change. Adding properties via categories is not impossible, but is much more difficult.
Class Extensions are best used for keeping properties your object needs, but are not intended to be public.
If you do truly need to add properties to this object, the way to do it is with the Objective-C runtime's associated objects
There's an excellent writeup of when/how to use them here

RestKit CoreData one to many relationship mapping, the To Many part not working

I am using RestKit 0.20 to map 2 entities.There is a one to many relationship.
Teacher<->>SchoolClass
Here is the Teacher.h
#class SchoolClass;
#interface Teacher : NSManagedObject
#property (nonatomic, retain) NSString * firstName;
#property (nonatomic, retain) NSString * lastName;
#property (nonatomic, retain) NSNumber * teacherId;
#property (nonatomic, retain) NSSet *teachesClass;
#end
#interface Teacher (CoreDataGeneratedAccessors)
- (void)addTeachesClassObject:(SchoolClass *)value;
- (void)removeTeachesClassObject:(SchoolClass *)value;
- (void)addTeachesClass:(NSSet *)values;
- (void)removeTeachesClass:(NSSet *)values;
#end
Here is the SchoolClass.h
#interface SchoolClass : NSManagedObject
#property (nonatomic, retain) NSString * classCodeId;
#property (nonatomic, retain) NSString * classDesc;
#property (nonatomic, retain) NSString * classRoom;
#property (nonatomic, retain) Teacher *classTeacher;
#end
The code for the relationship mapping is:
[classMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"teacher" toKeyPath:#"classTeacher" withMapping:teacherMapping]];
The results are that in the SchoolClass objects, the classTeacher properties are correctly added. However in the Teacher objects, the teachesClass properties are all empty. Is this expected behavior or I missed something?
Thanks
Ray
Somehow the problem is gone now. All the relationships now working fine. Not sure exactly what happened. Perhaps because I did a reset for the simulator after made a json change. Previously the json results had a problem that caused both side of the relationship problems. After it was fixed, the SchoolClass objects were fine but Teacher objects had relation problems. Now both are fine.

Setter for NSManagedObject creates _CDSnapshot_Provence_

I have two NSManagedObject:
DataEntered
Provence
There is a relation between them: DataEntered must have ONE Provence, and Provence may have one/multiple DataEntered.
All is working well, but when using Instruments and Allocations, every time I set the Provence to DataEntered, a new _CDSnapshot_Provence_ appears in #Living:
Provence * provence = [[self fetchedResultsController] objectAtIndexPath:indexPath];
[self.dataEntered setAddress_provence:provence];
The setter for Provence in DataEntered is managed by CoreData, there is no customization.
When I save DataEntered, is saved correctly. What can cause the creation of multiple living _CDSnapshot_Provence_ ?
Thanks!
#class Provence;
#interface DataEntered : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, strong) Provence *address_provence;
#end
#class Provence;
#interface DataEntered : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, strong) Provence *address_provence;
#end
#class DataEntered;
#interface Provence : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *dataEnteredAddress_Provence;
#end
#interface Provence (CoreDataGeneratedAccessors)
- (void)addDataEnteredAddress_ProvenceObject:(DataEntered *)value;
- (void)removeDataEnteredAddress_ProvenceObject:(DataEntered *)value;
- (void)addDataEnteredAddress_Provence:(NSSet *)values;
- (void)removeDataEnteredAddress_Provence:(NSSet *)values;
#end
#import "Provence.h"
#import "DataEntered.h"
#implementation Provence
#dynamic name;
#dynamic dataEnteredAddress_Provence;
#end
I saw exactly the same thing and I believe that this is to be expected.
See the section Conflict Detection and Optimistic Locking in the Apple docs at
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdChangeManagement.html
"When Core Data fetches an object from a persistent store, it takes a snapshot of its state. A snapshot is a dictionary of an object’s persistent properties—typically all its attributes and the global IDs of any objects to which it has a to-one relationship."
There is also a section at that same link that is useful to read - Snapshot Management
The problem I ran into was getting Core Data to release its memory allocations after I had faulted all the managed objects or did a context reset.
I just published a blog posting on this and related topics:
Core Data issues with memory allocation - http://finalize.com/2013/01/04/core-data-issues-with-memory-allocation/
Hope this helps.
Scott

Resources