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

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;

Related

Objective-C "Override" Specifier

In Java, C++11 and some other languages you can specify that a method is intended to override another method from a base class or interface, if you then at a later point remove the method from the base class you get a compiler error. I use protocols with optional methods a lot and find that if I remove a method from there I have a tendency to forget to remove the code that implemented the method. This does not generate an error or a warning, thus creating a "dead" method.
Consider:
#protocol Prot <NSObject>
#optional
- (void)bar;
- (void)tempBar;
#end
#interface MyType : NSObject <Prot>
#end
#implementation MyType
- (void)bar { /**/ }
- (void)tempBar { /**/ }
#end
If I at one point remove tempBar from the protocol, I would like to get at least a warning from tempBar being implemented in MyType.
Is there any way in Objective-C to specify that a method is expected to be an implementation of a protocol method?
Objective-C is a dynamic language and this is rather impossible to enforce at compile time. Note that in Obj-C you can actually call methods there are not even there and the app won't crash (well, the default implementation will raise an exception but you can change that behavior).
The method can be also added in an extension, or added at runtime. Or it is just not present in the header.
Note there is also the opposite problem. When subclassing, you can override a method which you don't even know is there, because it is not present in the headers.
This is one of the reasons why Apple is moving to a more predictable language, that is, Swift.

Overriding Delegate Methods when subclassing in Cocoa

Suppose I have a class Foo which declares a delegate protocol with 3 methods. I would like to subclass Foo into a class called Bar and completely override these methods.
Should I declare them in the subclass header again?
When I implement these 3 methods inside of Bar's delegate, do I have to take any precautions to make sure Foo's implementation will not be used?
Should I declare them in the subclass header again?
That won't be necessary, as your Bar.h will import Foo.h and therefore know it conforms that protocol.
When I implement these 3 methods inside of Bar's delegate, do I have
to take any precautions to make sure Foo's implementation will not be
used?
The only precaution you need to take is to not call [super delegateMethod]; on your implementations, and you're good to go.

overriding undeclared methods in subclass

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.

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.

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.