Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Objective-с doesn't have built-in method visibility like protected, private, abstract.
How to implement it like in Java?
Solution in my answer below
private method visibility - easily implemented inside .m files:
#interface SomeClass () <SomeProtocolForPrivateImplementation>
{
int _someVar1;
int _someVar2;
int _someVarN;
}
#property (nonatomic, readwrite) NSString *someProperty;
- (void)_somePrivateMethod;
#end
#implementation SomeClass
- (void)_somePrivateMethod
{
}
#end
protected and abstract method visibilities require Class Category, but it's not only one solution. You can use next model. For example you have abstract Data Model class which implements the basic mechanisms for working with some data, for example some synchronization. You need to create subclasses that will load the data in different ways. In java you can easily make it like this:
public abstract class AbstractDataModel
{
public abstract String getDataModelID();
protected void syncData()
{
// ... some data synchronization
}
}
public class DataModel extends AbstractDataModel
{
#Override
public String getDataModelID() {
// TODO Auto-generated method stub
return null;
}
}
But you can't do the same in Objective-сб you need to use Class Categories, it no so cool :( .
I found a way to do this in more elegant way using protocols:
In .h file:
#protocol ModelSubclassingProtocol;
#interface Model : NSObject
{
int _someVar;
}
#property (nonatomic, readonly) NSString *someProperty;
- (id)initWithDictionary:(NSDictionary*)info;
- (BOOL)updateFromDictionary:(NSDictionary*)info; // return TRUE if update has changes
- (void)reloadItems;
#end
// use protocol for subclasses
#protocol ModelSubclassingProtocol <NSObject>
#required
// all abstract methods here
- (Class)someAbstractMethod1;
+ (NSString*)someAbstractMethod2;
- (BOOL)someAbstractMethod3;
#optional
// all protected methods here
- (void)someProtectedMethod1;
- (BOOL)someProtectedMethod2;
#end
In .m file:
#define SUBCLASS ((id<ModelSubclassingProtocol>)self)
#interface Model () <SomeProtocolsForPrivateImplementation>
{
NSMutableArray *_somePrivateVar1;
}
#property (nonatomic, readwrite) NSString *someProperty1;
#end
#implementation RDModel
+ (id)alloc
{
// check subclassing protocol implementation
Protocol *protocol = #protocol(ModelSubclassingProtocol);
NSString *protocolName = NSStringFromProtocol(protocol);
NSString *className = NSStringFromClass(self.class);
NSAssert([self.class conformsToProtocol:protocol], #"\n\nERROR: \"%#\" must be conforms to protocol \"%#\".\nRecommended to use internal class extension in \"%#.m\", sample code:\n\n#interface %# () <%#>\n#end\n\n", className, protocolName, className, className, protocolName);
return [super alloc];
}
#pragma mark - Private
- (NSDictionary*)_synchronizeItems:(NSArray *)array
{
//... some implementation before
// use abstract methods here
NSString *itemIdentifier = [SUBCLASS itemIdentifier];
//... some implementation after
}
Sorry for bad english.
Related
I am trying to re-struct my project code with an inheritance style, what is the best practice for how to inherit property from parent class and override setter and getter?
I give the demo code, in the demo, ChartModel is a base class in a ChartViewController, and LineChartModel is a sub class of ChartModel in LineChartViewController.
I want to override the setter and getter of LineChartModel *dataModel in sub view controller. Please include any #synthesize and protected instance variable, or if it is automatically generated by compiler, please mark. Thank in advance.
// ChartModel.h
#interface ChartModel : NSObject
-(BOOL)hasData;
#end
// LineChartModel.h
#interface LineChartModel : chartModel
-(void)getLineColor;
#property (nonatomic, strong) NSArray* dataArray;
#end
// ChartViewController.h
#interface ChartViewController: UIViewController
#property (nonatomic, strong) ChartModel *dataModel;
-(void)updateUI;
#end
// ChartViewController.m
#implementation ChartViewController
-(void)updateUI {
if ([self.dataModel hasData]) {
[self.view setHidden:NO];
} else {
self.view.hidden = YES;
}
// setter and getter here
#end
// LineChartViewController.h
#interface LineChartViewController : ChartViewController
// pay attension here, same name but a sub class of chartModel
#property (nonatomic, strong) LineChartModel *dataModel;
#end
// LineChartViewController.m
#implementation LineChartViewController
//override dataModel setter here
//override dataModel getter here
#end
Technically, the only thing you need in the implementation of LineChartViewController is:
#dynamic dataModel;
That tells the compiler that the getter and setter will be supplied in some way it can't immediately see. In actuality, they will be supplied by the superclass.
However, that allows for a problem. A LineChartViewController is-a ChartViewController. That means that an instance of LineChartViewController can be passed to a method or function which is declared to take a ChartViewController and that method/function is entitled to do anything to it that is allowed by the interface of ChartViewController. That includes assigning an instance of ChartModel (not LineChartModel) to its dataModel property. Presumably, LineChartViewController will break if its dataModel property is not a LineChartModel.
In technical terms, your design violates the Liskov substitution principle.
It's not a fix for the design issue, but you can catch the problem at run time if it happens, by implementing an override of the setter like this:
- (void) setDataModel:(LineChartModel*)dataModel
{
if (dataModel && ![dataModel isKindOfClass:[LineChartModel class]])
{
NSString* reason = [NSString stringWithFormat:#"%# is not a valid dataModel for LineChartViewController; it must be a kind of LineChartModel", dataModel];
[[NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil] raise];
}
[super setDataModel:dataModel];
}
I have an object which implements various protocols (like 10 different ones).
For example
#interface MyClass <UITableViewDelegate,UITableViewDataSource,UISearchDisplayDelegate,...>
#end
#implementation
/// a whole bunch of methods for the delegates
#end
In order to "clean" things up in this class - I have created helper classes which encapsulates the logic pertaining to those delegates.
so now the new refactored class looks something like
// public interface which looks the same
#interface MyClass <UITableViewDelegate,UITableViewDataSource,UISearchDisplayDelegate,...>
#end
// private interface
#interface MyClass ()
// a bunch of objects which implement those methods
#property (nonatomic,strong) MyUITableviewDelegate *tableViewDelegate;
#property (nonatomic,strong) MyUITableviewDataSource *tableViewDelegate;
#property (nonatomic,strong) MySearchDisplayDelegate *searchDisplayDelegate;
// another bunch of objects which answer to the delegates
#end
#implementation
// all the delegate methods were moved out of here to the class which implements the method
#end
Now when an object of "MyClass" is assigned as a delegate - it should return the runtime object which "answers" to those delegates (for instance if "MyClass" object is assigned as a UITableViewDelegate - the MyUITableviewDelegate should be assigned.
How can this be done?
Must I override the forwardInvocation in the "MyClass" object?
You need to implement forwardingTargetForSelector:
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([self.tableViewDelegate respondsToSelector:aSelector]) {
return self.tableViewDelegate;
}
// etc
return [super forwardingTargetForSelector:aSelector];
}
There are many questions concerning the category-properties problem.
I know some possibilities to address this:
use a singleton registry
objc_setAssociatedObject and objc_getAssociatedObject
From my point of view both is not clean since the memory allocated is never cleared when the object that created such properties is deallocated.
Categories are a good way to keep code clean and dynamically add functionality to already existing classes. They help to group functionality and to distributed implementation work among more developers.
The bad about categories is the missing storage.
I came across this problem several times now and I'm wondering whether the following would address this problem in an clean way that also takes care about the memory and if there are any problems that I can't see right now.
There is one restriction, that I can ignore since I'm working as a framework developer: I'm able to create my own root class that all my other classes can inherit from.
First of all declare the new root object:
#interface RootObject : NSObject
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key;
- (id)runtimePropertyForKey:(id)key;
#end
With the corresponding implementation:
#import "RootObject.h"
#interface RootObject ()
#property (readwrite) NSMutableDictionary *runtimeProperties;
#end
#implementation RootObject
#synthesize runtimeProperties = _runtimeProperties;
- (id)init {
self = [super init];
if (self)
{
_runtimeProperties = [[NSMutableDictionary alloc] initWithCapacity:1];
}
return self;
}
- (void)dealloc {
[_runtimeProperties release];
_runtimeProperties = nil;
[super dealloc];
}
- (id)runtimePropertyForKey:(id)key {
return [self.runtimeProperties objectForKey:key];
}
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key {
if (key)
{
if (runtimeProperty)
{
[self.runtimeProperties setObject:runtimeProperty forKey:key];
}
else
{
[self.runtimeProperties removeObjectForKey:key];
}
}
}
#end
By using this RootObject instead of NSObject it should be very easy to add a "property" to a category on a class. Consider having some class MyClass
#interface MyClass : RootObject
// some interface here
#end
When implementing a special behavior on top of this class you are now able to add a property like this:
#interface MyClass (specialBehavior)
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSDate *birthday;
#end
With corresponding implementation:
#implementation MyClass (specialBehavior)
#dynamic name;
- (NSString *)name {
return [self runtimePropertyForKey:#"name"];
}
- (void)setName:(NSString *)name {
[self setRuntimeProperty:name forKey:#"name"];
}
#dynamic birthday;
- (NSDate *)birthday {
return [self runtimePropertyForKey:#"birthday"];
}
- (void)setBirthday:(NSDate *)birthday {
[self setRuntimeProperty:[birthday copy] forKey:#"birthday"];
}
#end
Such an implementation could KVO compatible as well by just adding the necessary calls in the setter method.
Very straight forward, but I'm wondering whether I missed something important? (E.g. very very bad runtime performance having many such declared properties or using many of these objects)
This is effectively the same as objc_setAssociatedObject and objc_getAssociatedObject, which do release memory when the object is deallocated (depending on the association type). I would guess they also have much lower overhead than your suggested code.
Newbie to objective C...
NOTE: This is a conceptual problem, as I'm trying to translate "public and private" from what I know about other languages.
How can I access the "stringB" ivar through the "public" method?
myClass.h
#interface myClass : UIViewController {
}
#property (nonatomic, retain) NSString *stringA;
#property (nonatomic, retain) NSString *stringB;
- (void)dealWithStringA;
+ (void)dealWithStringB;
myClass.m
#import "myClass.h"
#interface myClass () {
}
#end
#implementation myClass
// My "private" function
- (void)dealWithStringA
{
return _stringA;
}
// My "public" function
+ (void)dealWithStringB
{
// Errors with: Instance variable "stringB" accessed in class method
return _stringB;
}
The method starting with a + is called a class method in objective C where a method starting with - is an instance method. An instance method can be performed on an instance of that class only.
Also the return type for your method would be an NSString since you are expecting to get a string object from that method.
For a class method, you'll need to create an autoreleasing instance of that class and then perform operations on that instance.
For eg.
+ (NSString*)dealWithStringB
{
MyClass *myClass = [[[MyClass alloc] init] autorelease];
myClass.stringB = #"Its String B";//It's an absurd example
return myClass.stringB;
}
You are wrong with understanding "+", "-" - it's not about private / public.
To have a private function you should implement that in your .m file:
#interface YourClass ()
- (id) privateMethod;
#end
Everything you declare in .h file will be public:
#interface YourClass : NSObject
- (id)someMethod //public
#end
"+" is used for static functions so you can call them without having an instance of a class.
For example in your case:
[myClass dealWithStringB];
and for "-" function you need instance.
[[[myClass alloc] init] dealWithStringA];
The static functions can be used when you don't need any properties from a class or to they are pretty often used to create instances of classes.
The "+" prefix means class method, not public. A "-" stands for instance method, not private.
Both public and private methods can access the private state of the class or instance.
myClass.h (Similar to yours)
#interface myClass : UIViewController
{
}
#property (nonatomic, retain) NSString *stringA;
#property (nonatomic, retain) NSString *stringB;
- (void)dealWithStringA;
+ (void)dealWithStringB;
#end
myClass.m
#implementation myClass
#synthesize stringA ;
#synthesize stringB ;
static myClass* instance = nil;
+(void) dealWithStringB
{
if(instance==nil)
{
instance=[myClass alloc]init];
}
else
{
//Access the field this way
printf("#"The string content is %#",instance.stringB);
}
}
Hope its Clear!!!
I'm confused - I cannot understand what is the delegate is for?
The Application Delegate which is created by default is understandable, but in some cases I've seen something like this:
#interface MyClass : UIViewController <UIScrollViewDelegate> {
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;
BOOL pageControlUsed;
}
//...
#end
What is the <UIScrollViewDelegate> for?
How does it work and why is it used?
<UIScrollViewDelegate> is saying that the class conforms to the UIScrollViewDelegate protocol.
What this really means is that the class must implement all of the required methods defined within the UIScrollViewDelegate protocol. Simple as that.
You can conform your class to multiple protocols if you like:
#implementation MyClass : UIViewController <SomeProtocol, SomeOtherProtocol>
The purpose of conforming a class to a protocol is to a) declare the type as a conformant of the protocol, so you can now categorize this type under id <SomeProtocol>, which is better for delegate objects that objects of this class may belong to, and b) It tells the compiler to not warn you that the implemented methods are not declared in the header file, because your class conforms to the protocol.
Here's an example:
Printable.h
#protocol Printable
- (void) print:(Printer *) printer;
#end
Document.h
#import "Printable.h"
#interface Document : NSObject <Printable> {
//ivars omitted for brevity, there are sure to be many of these :)
}
#end
Document.m
#implementation Document
//probably tons of code here..
#pragma mark Printable methods
- (void) print: (Printer *) printer {
//do awesome print job stuff here...
}
#end
You could then have multiple objects that conform to the Printable protocol, which could then be used as an instance variable in, say, a PrintJob object:
#interface PrintJob : NSObject {
id <Printable> target;
Printer *printer;
}
#property (nonatomic, retain) id <Printable> target;
- (id) initWithPrinter:(Printer *) print;
- (void) start;
#end
#implementation PrintJob
#synthesize target;
- (id) initWithPrinter:(Printer *) print andTarget:(id<Printable>) targ {
if((self = [super init])) {
printer = print;
self.target = targ;
}
return self;
}
- (void) start {
[target print:printer]; //invoke print on the target, which we know conforms to Printable
}
- (void) dealloc {
[target release];
[super dealloc];
}
#end
I think you need to understand the Delegate Pattern. It is a core pattern used by iphone/ipad applications and if you don't understand it you will not get far. The link to wikipedia I just used outlines the pattern and gives examples of it's use including Objective C. That would be a good place to get started. Also look at take a look at the Overview tutorial from Apple which is specific to the iPhone and also discusses the Delegate pattern.