When you wonder about anything that seems "weird" in Swift, most of the time the answer is "because of Objective-C".
For some perspective, I consider 3 access level common to many modern programming languages:
private
: only accessible to the class in which it is defined.
protected
: only accessible to the class in which it is defined and its subclasses.
public
: accessible to any outside program.
Let's take one step further back, to the world of C. C has no access modifier whatsoever, not being an OOP language. However, in reality, it's closer to having a private / public system. If you want other programs to know your symbols (functions, macros, data types, etc.), you define them in your header (.h
) file. If not, you define them in your source (.c
) file or a private header file. Whatever program interested in your symbol will include the corresponding header file:
#include "foo.h"
This #include
is no more than a compiler-assisted copy & paste. The compiler copies all the symbols in foo.h
and redeclare them in your source file.
Since Objective-C is a strict superset of C, every valid C program is also a valid Objective-C program. Objective-C continues this tradition: declare your public methods in the header file, keep private methods declaration to the implementation file:
// ------------------------------------------
// MyClass.h
// ------------------------------------------
@interface MyClass: NSObject
- (void) publicMethod;
@end
// ------------------------------------------
// MyClass.m
// ------------------------------------------
#import "MyClass.h"
// Declare your private methods here.
// You can move this to a separate file, i.e. MyClass+Private.h if you want
@interface MyClass()
- (void) privateMethod;
@end
@implementation MyClas
- (void) publicMethod () { ... }
- (void) privateMethod() { ... }
@end
So at glance, Objective-C seems to inherit C's system of public / private declarations. However, Objective-C is a very dynamic language. You can query its runtime for all methods to a class, private or public. Access control in Objective-C is more about "use what I tell you in the documentation" rather than "this method is off limit to you".
This poses a paradox: how do you implement protected
in Objective-C? It has no good answer for that. One common pattern is to move all protected methods into a separate declaration file and import them into the main class and subclass's implementation:
// ------------------------------------------
// MyClass+Protected.h
// ------------------------------------------
@interface MyClass (Protected)
- (void) protectedMethod;
@end
// ------------------------------------------
// MySubClass.m
// ------------------------------------------
#import "MyClass+Protected.h"
...
Swift simply carries on that tradition, for better or worse. There is an accepted proposal to change this in Swift 3. If anything, Chris Lattner and the Swift team has shown little affinity for the past and the legacies of C. You can see evidence of that in Swift 2.2 with the removal of ++
and C-style for
loops.