I have created a Game Model as a class. I checked out this question about creating a class extension: Best way to define private methods for a class in Objective-C
What I have is some public methods - these are open for other VCs to use in the app.
I also want some private methods, that the classes public methods can make use of, but do not need to be open to the rest of the application as such.
I thought this could be accomplished by a class extension, adding an extra interface section in the implementation file but this doesn't appear to work.
Imp file:
#import "MESGameModel.h"
#interface MESGameModel ()
-(BOOL)checkIfGameAlreadyExistsAgainst:(PFUser *)opponentUser;
#end
#implementation MESGameModel
#pragma mark - Public methods
+(void)createNewGameAgainst:(PFUser *)user2 withCompletion:(void (^)(BOOL success))completionHandler{
Later on I have the declaration of the other private method:
#pragma mark - Private methods
-(BOOL)checkIfGameAlreadyExistsAgainst:(PFUser *)opponentUser {
What I am looking for is the ability to call for example [self checkIfGameAlreadyExistsAgainst...] within the public method (createNewGameAgainst).
Your createNewGameAgainst method is a class method (see the + in front of the method declaration). Your checkIfGameAlreadyExistsAgainst method is a instance method (see the - in front of the method declaration). To call checkIfGameAlreadyExistsAgainst from createNewGameAgainst you need to get an instance of MESGameModel. self inside of createNewGameAgainst references the class itself, not an instance of it.
You can use the form; your problem is understanding the distinction of class methods vs instance methods.
+ (void)createNewGameAgainst:(PFUser *)user2 withCompletion:(void (^)(BOOL success))completionHandler
Is a class method (note the '+') -- you do not need an instance of MESGameModel to call this method. However, you will have no instance of MESGameModel within the definition (or body of) that class method. You cannot use the instance methods, properties, or ivars of the MESGameModel because the instance of MESGameModel is absent in a class method.
self in this scope will be a special class which you can message but responds to the class methods.
- (BOOL)checkIfGameAlreadyExistsAgainst:(PFUser *)opponentUser;
Declares an instance method (note the '-'). An instance of MESGameModel may respond to this message, and within that method's definition, you will have access to the instance variables, properties, instance methods, and class methods of MESGameModel.
self will be an instance of MESGameModel which you can message, and responds to the instance methods.
Related
Imagine I have define a class MyClass as follows:
The class interface file:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#property (nonatomic) NSString *myProperty;
- (void)myPublicMethod;
#end
The class implementation file using categories:
#import "MyClass.h"
#interface MyClass (MyCategory)
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPublicMethod {
NSLog(#"myPublicMethod was called!");
[self myPrivateMethod];
}
- (void)myPrivateMethod {
NSLog(#"myPrivateMethod was called!");
}
#end
An alternative class implementation file NOT using categories:
#import "MyClass.h"
# implementation MyClass
- (void)myPublicMethod {
NSLog(#"myPublicMethod was called!");
[self myPrivateMethod];
}
- (void)myPrivateMethod {
NSLog(#"myPrivateMethod was called!");
}
#end
Was hoping someone could explain the difference between the two implementation file approaches.
Is it the case that using categories means the "private" methods are inherited by any subclasses of MyClass and not using categories means the "private" methods are not inherited by any subclasses?
All methods that exist on a class are always inherited and are callable by anyone regardless of how you declare them. The main difference is whether anybody knows about them. There was also a historic need to declare things before use which leads to internal forward declarations in older and old-style code.
A category is used to add methods to an existing class. A common use is to extend the functionality of one of the existing classes. For example you might implement:
#interface NSURL (HTTPQueryParameters)
- (NSDictionary *)httpQueryParameters;
#end
So from then on you've given NSURL itself the knowledge required to parse HTTP protocol query parameters. It's often the correct factoring to add functionality directly to classes you don't have the source for.
Objective-C used to follow the C rule that methods had knowledge only of those methods that had preceded them within the compilation unit. So to be able to call a method that appeared later in the source file you'd need a forward declaration. If you didn't want to publish that method for the world to see you could achieve that with a category or a class extension (which for this purpose is just an unnamed category).
Nowadays Objective-C methods can call any method that is defined anywhere within the compilation unit, including subsequently in the same source file. It's therefore now normal not to collect up your unpublished methods into a category or an extension just for the benefit of the compiler.
That leaves categories for:
adding functionality to existing classes; and
segmenting your classes if they become very large;
Class extensions are now primarily for:
declaring #propertys without publishing them.
In Objective-C any method call can be sent to any object — objects are dynamically typed. So there's a mapping table in memory at runtime for every class from method name to implementation. The lookup process is to see whether the method is implemented in the class dispatched to. If not then dispatch to the superclass. An exception will be raised if the runtime runs out of superclasses.
The declaration of the method in a category #interface only serves to expose the method to users of the class, including -- as you mentioned in your comment -- subclasses.
(It would be much more usual to use a class extension (sometimes called an "anonymous category") declare a method that you're defining in the main implementation block. Actually, I'm not 100% sure what the interaction is between your category declaration and the main block definition -- I wouldn't have been surprised if it didn't compile, but it does.)
Thus, the only difference between your two examples is that the declaration allows you to create a private header in a situation where you want your own subclasses to access this method, but have framework users who you want to restrict.
How can I get super class instance?
id superObject=super;
Xcode says, "Use of undeclared identifier super"
It's not completely clear to me what you are trying to do, but based partly on your comments to your own question here is a guess.
It seems you may be confused over super in both Objective-C and Java. Both these languages are based on inheritance where a subclass instance is also an instance of its superclass. In neither language is there the concept of a "superclass instance/object". The meaning of super in the two languages is essentially the same, but differs in detail due to the different way the two languages support hiding.
In Objective-C super is a keyword while self, which references the instance a method was called on, is a variable (and the equivalent of Java's this). The super keyword is used to call a method on self but to start the search for the implementation to call in the superclass instead of the current class. It is usually used by an overriding method to call the method it has overridden.
However in your comments you also write:
I want to add a target with a method implemented in super class
which suggests you are trying to use an API which uses the target/action pattern, e.g. NSControl and others.
If the method you wish to call is not overridden in the current class then simply passing self as the target will invoke the superclass method. For example:
#interface Base : NSObject
- (IBAction) actionOne:(id) sender;
- (IBAction) actionTwo:(id) sender;
#end
#interface Child : Base
...
#end
#implementation Child
- (void) setActionFor:(NSControl *)aControl
{
aControl.target = self;
aControl.action = #selector(actionOne:); // actionOne is NOT overridden in Child
}
...
However if your subclass overrides a superclass method and you wish to set the superclass implementation as the action then you must write a method in your subclass which invokes the superclass method. For example, expanding on the previous example and passing Base's actionTwo as an action in a Child method when Child overrides actionTwo:
#implementation Child
// override Base method
- (IBAction) actionTwo:(id)sender { ... }
// provide a way to directly invoke Base method bypassing override
- (IBAction) superActionTwo:(id)sender
{
[super actionTwo:sender];
}
- (void) setActionFor:(NSControl *)aControl
{
aControl.target = self;
aControl.action = #selector(superActionTwo:); // indirectly set Base's actionTwo
}
HTH
Your self in-turn consist your super. You can access your super properties through self.
There isn't a separate object that represents your "super" object. Self is an instance of your class, which is part of a class hierarchy. When you call a method using the super keyword, you're specifying that you want to use your super class's implementation of that method. If your subclass doesn't override a method defined in super, then performing the selector on self will trigger a miss on your class's method lookup table and find the method definition on your superclass.
So, the simple answer is you should be able to accomplish what you're trying to do through self =]
Here you are trying initialize object with a class, not with instance of this class.
May be something like this?
id instance = [super init];
Say that Apple has an API defined in a private header file:
// Can't see this at all
#interface NSThing
- (void)secretMethod;
#end
and I have a category:
#interface NSThing (Helpers)
- (void)secretMethod;
#end
Does this override Apple's implementation and will their other private methods start calling into my implementation?
From "Avoid Category Method Name Clashes":
If the name of a method declared in a category is the same as a method
in the original class, or a method in another category on the same
class (or even a superclass), the behavior is undefined as to which
method implementation is used at runtime. This is less likely to be an
issue if you’re using categories with your own classes, but can cause
problems when using categories to add methods to standard Cocoa or
Cocoa Touch classes.
So if you "accidentally" implement a category method with the same name as
an existing method (private or not), the behaviour is undefined.
You should therefore prefix your category methods with a prefix that makes
name clashes unlikely.
I've implemented +resolveInstanceMethod on a class that subclasses NSDictionary. I will dynamically add methods to my class for certain cases, but I want standard NSDictionary methods to 'just work'.
I thought this would be the case if I just call [super resolveInstanceMethod:sel]; at the end of my method but it doesn't work.
+ (BOOL) resolveInstanceMethod:(SEL)sel
{
BOOL value = [super resolveInstanceMethod:sel]; // this is always NO!?
return value;
}
Why is this? How do I get my class to behave 'normally' for existing methods on the superclass?
What leads you to expect that -resolveInstanceMethod: would return YES for already existing methods? The release notes which introduced the new method say that the default implementation simply returns NO:
The NSObject class implements these methods with a default
implementation that returns NO today, though you should still invoke
it even if you're just directly subclassing NSObject.
In any case, it should never even be called for methods which are already present on the class. It's only called when you message an object with a selector which isn't already "resolved" to an implementation.
So we have a library with header files as below (for instance):
Public
MyCustomClass.h (subclasses MyClass)
Private
MyClass.h
When this is imported into an app however it then complains that it can't find MyClass.h. This is fair enough. Its #imported into MyCustomClass.h and yet its hidden.
So I changed it to a forward class declaration #class MyClass. Now it complains that I can't use a forward declaration for a super class (also makes sense).
How can I get around this then? I need to subclass something, but I only want people using the library to have access to the child class, not the super class.
You're writing a library, and you want clients to instantiate MyCustomClass which inherits from MyClass. But clients should not ever instantiate MyClass.
Approach 1: You don't actually need or want to hide MyClass. You just want to avoid instantiating instances of it.
a) Make its constructor private
b) Create a factory method that creates instances of MyCustomClass.
The factory might be part of MyClass, or it could be elsewhere.
#implemenation MyClass
+ (MyCustomClass*) createWith: (Param*) someData;
Approach 2: consider composition rather than inheritance. Let MyCustomClass own an object of type MyClass, and let it do all the work:
#implementation MyCustomClass
#property (nonatomic,strong) MyClass* myClassInstance;
- (void) doSomething
{
[self.myClassInstance doSomething];
}
Since clients can't subclass MyClass anyway, the inheritance is an implementation detail. Don't inherit when you don't need to.
Approach 3: Are you sure you really want to expose MyCustomClass? Is it really an object, or is it a protocol? Perhaps your library should offer the interface publicly, and both MyClass and MyCustomClass are private implementations.