3

Can someone walk me through how to 'hide' the standard core data setters?

I know there is not really a way to define 'Private' methods in Objective-C, but read about using an extension to achieve a similar result. The problem is, I want to apply this to core data classes. I would like to hide the standard setters created for some attributes, and only call them from inside other, exposed setters.

An example: My core data object has a BOOL 'collected' and a date 'dateCollected'. I have figured out how to add setDateCollected to setCollected, but now I would like to 'hide' set collected so that it can't be called directly so easily (when I might forget to also set dateCollected manually).

To clarify, the part that is tripping me up is the '@dynamic' calls - I don;t know where these should live.

EDIT - I guess I missed a part. I can move the @property declaration into the implementation file just fine. But I want the setter to be hidden, and the getter to remain public. I guess I need to replace the @property, but I don't know how to do this for a core data object.

Ben Packard
  • 26,102
  • 25
  • 102
  • 183

2 Answers2

1

What you are trying to do is not likely to lead to a good result. Core Data classes are very delicately set up with graph hierarchies and the property implementations live in the superclass. Perhaps you should elininate the collected variable and just do a nil check on dateCollected. Another slightly more convoluted way would be to remove it from the data model and make it a regular ivar.

EDIT: Alright, I took a look at the info in your comment. It does indeed suggest that you can override the implementation if you adhere to certain guidelines. However, the answer below is probably better. Move the property to the private interface. Then declare another property in the public interface (readonly) that returns the value of the private property ;).

borrrden
  • 33,256
  • 8
  • 74
  • 109
  • The dateCollected is a simplified example (nice idea though). Moreover, I thought it was pretty standard practice to redefine setters, as long as I use willChangeValueForKey and didChangeValueForKey. Or maybe you mean just the 'hiding' aspect is ill advised? I don't see why that would be the case, since the standard setters will still exist, I'm just not exposing them to the compiler. – Ben Packard Apr 03 '12 at 00:36
  • I dont know if it is standard or not but I am using 9 or 10 Core Data classes in my project as is. The scary part about overriding Core Data is that I dont know exactly what NSManagedObject is doing, and doing it wrong is a fast ticket to EXC_BAD_ACCESS land. Or did you find this information somewhere? Maybe someone smarter than me has a better answer but until then ^^; – borrrden Apr 03 '12 at 00:46
  • I was just working from a combination of http://stackoverflow.com/questions/172598/best-way-to-define-private-methods-for-a-class-in-objective-c and http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdAccessorMethods.html – Ben Packard Apr 03 '12 at 00:51
  • Ah, well that's interesting, however I think the person below is on a safer track so I updated my answer. However, since it is based on his answer...I won't take credit ~^^ – borrrden Apr 03 '12 at 01:10
  • Thank you - It was really that simple :) – Ben Packard Apr 03 '12 at 01:34
0

You define private methods in the implementation file. If a method is not shown in the header file, then by definition, it is private. To clarify, the following is how you define public properties and methods.

@interface MyAppViewController : UIViewController

@property (strong, nonatomic) NSString *myPublicStringObject;

- (NSString *) myPublicMethodTakingInputString:(NSString *) input;

@end

In the implementation file, you can define private properties and methods as follows.

#import "MyAppViewController.h"

// Declare private properties and methods inside the following interface extension
@interface MyAppViewController ()

@property (strong, nonatomic) NSNumber     *myPrivateNumber;
@property (strong, nonatomic) NSString     *myPrivateStringObject;

- (void) myPrivateMethod1;
- (NSString *) myPrivateMethod2WithIntegerInput:(NSInteger) input;

@end


@implementation MyAppViewController

@synthesize myPublicStringObject;
@synthesize myPrivateNumber;
@synthesize myPrivateStringObject;

// Implement all methods declared in header and private interfaces here in no particular order
- (NSString *) myPublicMethodTakingInputString:(NSString *) input
{
// code for myPublicMethodTakingInputString
}

- (void) myPrivateMethod1
{
}

- (NSString *) myPrivateMethod2WithIntegerInput:(NSInteger) input
{
}


// Implement any other private method not declared
- (NSString *) myUndeclaredPrivateMethod1:(NSString *) input
{
// code for myUndeclaredPrivateMethod1
}


- (id) myUndeclaredPrivateMethod2
{
// code for myUndeclaredPrivateMethod2
}

... etc.

This description is for iOS 5 of course. The syntax for iOS3 & 4 is similar except that the private instant variables (iVars) appear in the header file--which could be very confusing for newbies. iOS 5 cleaned this up, by not requiring instant variables to appear anywhere.

Sunny
  • 1,464
  • 14
  • 26
  • This is close - I guess I missed the important part (updated the Q, my apologies) - I need to keep the getter public, so I guess I have to replace the @property, but not sure if there is special behavior for core data entities. – Ben Packard Apr 03 '12 at 00:59
  • You can implement a category for core data objects. Look up categories in the documentation. They look like private interfaces except that categories have the category name inside the braces. E.g., a category to create my example object above might look like \@interface MyAppViewController (Create) //"my code" \@end. Inside "my code" will be all the method i'd call to create the object. – Sunny Apr 03 '12 at 02:52
  • In general, you can keep the setters private by overriding the setter portion of @property. E.g. for my object "\@property (strong) NSString myObject;" I could override the setter with "- (void) setMyObject:(NSString *) string { //setter code }" Now, this gets called each time someone wants to assign to the property. Voila! – Sunny Apr 03 '12 at 03:09