overriding undeclared methods in subclass - objective-c

I have a class with some methods neither declared in .h file nor in any category, I want to override these methods in the subclass to change the behavior slightly. I am thinking of simply redefining those methods in subclass. Is it a good idea? would it even work?

Ideally the subclass needs to know what the methods are if it wants to override the method and still call super.
One way of doing this is by having a separate header file which both the super class and subclass implementations both import.
// MyClass_protected.h
- (void)someMethodThatYouWantSubclassesToBeAbleToOverride;
Then
// MyClass.m
#import "MyClass_protected.h"
// MySubClass.m
#import "MyClass_protected.h"

It'll 'work' in that the compiler allows it. The class that defines these methods probably assumes they do particular things when called, which your implementation needs to respect when overriding them to avoid introducing bugs in the use of the class's interface.

You can override private methods in a base class but the problem is that you can't call [super someMethod]. If you wish to completely replace the original method then this isn't an issue.
Otherwise you need to let the derived class know about the methods in the parent class.

Related

Objective-C – How to hide methods for a class that implements a protocol

Question is in title. Code example:
UIViewController <MyProtocol> *viewcontroller = ...;
[viewcontroller methodFromProtocol]; // I expect to be able to call all methods that the protocol defines
//UIViewControllerSubclass implements MyProtocol
UIViewControllerSubclass *viewControllerSubclassWithoutMyProtocol = [[UIViewControllerSubclass alloc] init];
[viewControllerSubclassWithoutMyProtocol methodThatIsNotInTheInterfaceIsDisplayedHere]; // I only expect to be able to call the methods that are defined in this class' interface even though this class implements MyProtocol
Your question isn't completely clear, but I think you are asking if you can "privately" conform to a protocol?
This can be done by declaring that you conform to the protocol inside the implementation file, rather than the interface file. With view controllers, you can do this in the class continuation that is generated for you automatically in the .m file, otherwise you'll need to add the class continuation in yourself:
#interface MyVCSubclass () <MyProtocol>
Now, any class that imports only the header file will not know your controller conforms to the protocol.
[viewControllerSubclassWithoutMyProtocol methodThatIsNotInTheInterfaceIsDisplayedHere];
I only expect to be able to call the methods that are defined in this class' interface even though this class implements MyProtocol
That's a bad expectation. Objective-C lets you call any method that an object implements. If you try to call a method that an object doesn't implement, two things should happen:
You get a compiler warning (not an error though)
When the code runs, it crashes, unless you've taken steps to handle such an event.
If a class implements a protocol but doesn't declare that it does so in a public header, then you can still call the method (since Objective C doesn't have private methods). I'd have thought you'd get a compiler warning, but if you're calling this from a file within the same Xcode project as your object (that is, you're not building a static library) then it's possible that Xcode is getting smart and deciding that since the method exists, it must be OK to call.
It wasn't clear from your question what you expected to happen and what actually happened. If you supply that information, we'll be able to give better answers.

Guidelines for declaring methods in #interface, in an extension, or not declaring at all

I've been learning Object Oriented Programming in Objective-C and I'm a little confused about method declaration and implementation.
In some lectures I've been studying, the professor declares public methods in the .h file and then implements them in the .m file; or he may declare them private in the .m file and them implement them in the #implementation ClassViewController section.
Sometimes, however, he doesn't declare methods at all and just skips to method implementation in the #implementation ClassViewController section.
How do I make this distinction where to declare something either public or private, or not having to declare anything at all?
Methods should be declared publicly when you want that method to be accessible to outside classes, and privately otherwise. A method that was declared in a superclass does not need to be declared again in it's subclasses if you override it. As far as methods that are implemented without any previous declaration, that method can still be called, but it is only 'visible' to methods below it in the file, and will throw a warning otherwise. As such, this is rarely done (it is declared privately instead), with the exception of if that method is intended to be the target of an #selector.
The short answer is that all methods should be declared (either publicly or privately).
But I suspect what you actually saw your professor do was override a method that was already declared in a superclass.
So for example, if you wanted to override viewDidLoad in your CustomViewController, you would not declare viewDidLoad again, because that method was already declared in the header for UIViewController (the superclass).
You would simply go to the implementation of your subclass and write your implementation of viewDidLoad which would override the one you inherited. If you go watch the lecture again, I'm guessing that is what you saw.

In ObjC, how do I hide implementation a superclass's methods in a subclass?

In ObjC, how do I hide implementation a superclass's methods in a subclass?
I'm not sure if #private would do the trick, as it appears to only apply to ivars.
You're right, the #private directive is for instance variables, not methods. To hide a method's implementation, simply omit its declaration from the header file. To suppress warnings, you can use use a category or class extension to declare the method in the .m file.
There's no built-in language feature to prevent a subclass from seeing the method, though. Why would you want to do that?
There are no actually "private" methods in Obj-C; since any message can be sent to any object at runtime, there's no way to prevent someone from sending the message you care about.
That said, you can intercept that message in the subclass and not handle it. The simplest way to make a superclass's method inaccessible is to override it in the subclass and do nothing:
- (void)someMethodIDontWantToSupport
{
}
MARK as in subclass interface file.
- (void)someMethodIDontWantToSupport __unavailable;

When to define methods on interface and when not to?

I'm using a Objective-C framework for game development called Cocos2d-iphone.
This is how I create a button-graphic in the game:
CCMenuItemImage *battle;
battle = [CCMenuItemImage itemFromNormalImage:#"BattleFightOption1.png" selectedImage:#"BattleFightOption2.png"
target:self selector:#selector(battleFightOption)];
Basically, when the user clicks the button, method battleFightOption runs.
But I wonder, I never did define battleFightOption in the interface.. so, my question is: when is it necessary to define a method in the interface, and when is it not?
In short, every method that is meant to be used from outside the class must be declared in the interface; methods that are internal to the class implementation are omitted. The latter are typically declared in a class extension.
When you use a selector like #selector(methodName:), methodName: is called dynamically at runtime. The compiler doesn't have to know where it is, and doesn't check that the method exists when you compile.
However, it is still a good idea to declare it privately, which is generally done by putting an unnamed category at the top of the .m file (generally referred to as a class extension):
#import "Class.h"
#interface Class ()
- (void)privateMethod;
#end
#implementation Class
...
Anything that you intend to be public, called outside of the class, should be defined in the interface. If you are going to only use #selector(battleFightOption) you really do not need to define the method anywhere but I would recommend that you add a definition in the class extension just as you would any other private method.

how to block a superclass method to be called to a subclass

I'm extending the functionality of a class with a subclass, and I'm doing some dirty stuff that make superclass methods dangerous (app will hang in a loop) in the context of the subclass. I know it's not a genius idea, but I'm going for the low-hanging fruit, right now it's gonna save me some time. Oh it's a dirty job, but someone's gotta do it.
Bottom line, I need to either block that method from outside, or throw an exception when it's called directly to the superclass. (But I still use it from the subclass, except with care).
What would be the best way to do this?
UPDATE ---
So this is what I went for. I'm not self-answering, as Boaz' answer mentions multiple valid ways to do this, this is just the way that suited me. In the subclass, I overrode the method like this:
- (int)dangerousMethod
{
[NSException raise:#"Danger!" format:#"Do not call send this method directly to this subclass"];
return nil;
}
I'm marking this as answered, but evidently that doesn't mean it's closed, further suggestions are welcome.
Just re-implement the unsafe method in your subclass and have it do nothing or throw an exception or re-implement it as safe, just as long as the new implementation doesn't call the unsafe superclass method.
For the C++ crew in here: Objective C doesn't let you mark methods as private. You can use its category system to split up the interface into separate files (thus hiding 'private' ones), but all methods on a class are public.
You can override whichever methods you want to block in your subclass's .h file. You can make dangerousMethod unavailable by placing the following in your .h file.
- (int)dangerousMethod __attribute__((unavailable("message")));
This will make the dangerousMethod method unavailable to anyone using your subclass.
To keep other code from using the superclass's version this method, you can further restrict by putting this in your .m file.
- (int)dangerousMethod
{
return nil;
}
note: I'm ObjC/Cocoa newcomer:
#implementation MyClass
-(void)myMethod:(NSString *)txt{
if([self class] != [MyClass class]) return;
NSLog(#"Hello");
}
#end
Peter
This article explains how to create private variables in Objective C. They aren't truly private, but from what I read, the compiler will throw a warning if you try to call them from the subclass.
If you create the methods in your superclass as "private" then the subclass has no possible way of calling them. I'm not familiar with Objective C, but every other object oriented language I've seen has the "private" qualifier.