How to inherit from NSTokenAttachmentCell in Swift? - swift

In Swift (and objective-c), you cannot normally subclass NSTokenAttachmentCell. However, if I create a bridging header and define a header for NSTokenAttachmentCell, I can then subclass it in Swift.
Here is an example of it in objective-c. NSTokenAttachmentCell isn't publicly available. However, if you create a header file for it, you can subclass it. You can't create header files in Swift. Other than creating one in a bridging header, is there a way to do this in Swift?
#import <Cocoa/Cocoa.h>
#import "NSTokenAttachmentCell.h"
#interface BWTokenAttachmentCell : NSTokenAttachmentCell {}
#end

I created a Swift system module swift package init --type executable. The only file in addition to the standard SPM files was the custom header file that wasn't publicly available.
I can now use the system module package as a dependency and subclass the Apple class that you can't normally subclass.
Here is the full example.
git clone https://github.com/saltzmanjoelh/TokenExample && cd TokenExample && swift test
You will see the correct inheritance
Success: - <TokenExample.CustomTokenAttachmentCell: 0x7fc1be803d10> #0
- super: NSTokenAttachmentCell
- super: NSTextAttachmentCell
- super: NSCell
- super: NSObject
I used these two guides as a reference:
ship-c-code-with-swift-packages
importing-c-library-into-swift

The simple answer is no, you can't inherit from private classes.
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.
source: https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html

Related

Why does Swift allow access of private variables in the same file?

I've just found out that Swift's private access modifier is file level, as stipulated in the docs under "Access Levels":
Private access in Swift differs from private access in most other languages, as it’s scoped to the enclosing source file rather than to the enclosing declaration. This means that a type can access any private entities that are defined in the same source file as itself, but an extension cannot access that type’s private members if it’s defined in a separate source file.
So this means the following code will compile when the types are in the same file:
class FirstType {
private var privateProperty: String = ""
}
class SecondType {
private let firstType = FirstType()
func messWithFirstType() {
firstType.privateProperty = "👻" // this compiles and works!
}
}
As far as I can see, this breaks encapsulation completely. On the other hand, it might be nice to have some related types grouped together in the same file for readability, especially if the related types are tiny, like enums.
Private extensions are an exception because they are extending the same type the file is meant to contain. And private extensions do bring some nice things.
Are there any other reason, apart from facilitating private extensions, for the file scope private access modifier to be in Swift?
It isn't clear to me why private was originally implemented with regard to files, but rest assured that the Swift folks know this is not the only possible meaning of private and that it isn't ideal for some purposes, and are working to change it. There's already a proposal on the table, accepted for Swift 3, that will turn the current private into fileprivate and add a new level of private that will be scoped to the type rather than the file. You can expect to see this become part of Swift 3 in the very near future.
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.

How to declare Objective-C method with custom Swift class in it

I want to declare an Objective-C method with a custom Swift class as one of it's arguments, like this:
+ (void)doCalculationsWithACustomSwiftObject:(CustomSwiftClass *)swiftObject andADictionanary:(NSDictionary *)ordinaryDictionary;
The aim is to call this method from Swift, pass an instance of the custom class "CustomSwiftClass.swift" so that the Objective-C code can access its properties. Is it possible, and if so, how do I declare the "CustomSwiftClass" to make the compiler accept it?
A couple of thoughts:
To make Swift class accessible to your Objective-C code, you have to import the system generated header. As the documentation says:
When you import Swift code into Objective-C, you rely on an Xcode-generated header file to expose those files to Objective-C. This automatically generated file is an Objective-C header that declares the Swift interfaces in your target. It can be thought of as an umbrella header for your Swift code. The name of this header is your product module name followed by adding "-Swift.h". (You’ll learn more about the product module name later, in Naming Your Product Module.)
For example, your Objective-C file would import this generated header:
#import "MyApp-Swift.h"
For more information, see Importing Swift into Objective-C section of the Using Swift with Cocoa and Objective-C: Mix and Match
If you're not seeing the xxx-Swift.h file, double check your target settings:
(Note, I searched for "swift" in the settings to narrow down the results.)
As you'll see, the following are all set:
"Install Objective-C Compatibility Header" is set to "Yes";
The "Objective-C Generated Interface Header Name" is set (and matches what I imported into my Objective-C code);
The "Objective-C Bridging Header" is also specified.
Note, the Objective-C bridging header is ostensibly solely for the purpose of making the Objective-C classes available to the Swift code (and you're currently trying to accomplish the converse), but I notice that this affects what code is generated in the compatibility header, too. So make sure you have a bridging header, too.
Of course, make sure your Swift file is included in the list of compile sources:
And make sure the class is subclassed from NSObject:
import UIKit
class MyObject: NSObject {
var text: String?
var value: Int = 0
}
Note, some Swift types are not available to Objective-C code. For example, Objective-C cannot not use some optional types (e.g. an optional type such as Int? will not work, whereas an optional class type of String? will). So if you are seeing the class, but not some of the properties, make sure they're Objective-C compatible.
But I gather from your question that you're having more fundamental problems, that you're not finding the -Swift.h header at all. But once you solve that, this is a consideration for individual properties.

Objective-C Private Method Dilemma

I'm aware that Objective-C doesn't support real private methods. What I'm currently doing to declare 'private' methods is adding the following to class .m files:
#interface MyClass()
- (void) privateMethodName;
#end
The Problem:
If I now add a subclass, and want to use this 'private' method, I can't! I get the error:
Receiver type 'SubClassName' for instance message does not declare a
method with selector 'privateMethodName'
So, if I don't want non-subclasses to be able to access this method, but do want subclasses to be able to, what can I do? What is the best/proper way of achieving my goal?
You could separate the "protected" interface from the public one. In the primary header, just declare the public methods:
MyMagicThingy.h:
#interface MyMagicThingy: NSObject
- (void) publicMethod;
#end
Then, have an additional header with protected methods:
MyMagicThingy+Protected.h:
#import "MyMagicThingy.h"
#interface MyMagicThingy (Protected)
- (void) protectedMethods;
#end
You cannot have "real" private/protected/public methods in Objective C (as in: the compiler will enforce access rules. All methods are public). You have to go with a convention.
What you describe is really a protected method. One approach to overcome this: Ivars can be declared #public, #protected, or #private. You could declare a protected helper instance to restrict access to derived instances, which then calls back through the object which holds it.
Another alternative in some cases would be to make the subclasses write to an interface, then keep your implementation private.
Sometimes, you just have to document "don't do this, unless you are not a subclass" because it's not part of the language. In this mindset, a separate header which declares a category of protected methods is one of my favorite. It's pretty well hidden from clients, but can be made visible to subclasses by explicit inclusion -- Dirk provided an example of this at the same time, check it out.
Lastly, if you're comfortable with ObjC++, C++ offers this control, so you can mix modes and visibility quite freely.
First and foremost
You can't get anyone to not being able to call any method that is implemented on an object in Objective-C (at least not without burning through several dozen razors making Yaks less weatherproof).
Just don't call methods that are not declared in public header files, as a convention (this is, what you're already doing).
Second
The word public in the above paragraph does the trick:
In Objective-C (at least in its current incarnation), a class's interface can be defined over any number of header files using the technique you just described in your post: Class continuations.
One such example of an Apple framework class doing that would be UIGestureRecognizer with its separate subclassing header UIGestureRecognizerSubclass.h.
PS:
The error you are seeing reeks of using ARC so your runtime is definitely recent enough to even use multiple implementation files for that.

iOS Static Library And Method Hiding

I'm working on a static library for iOS and want to implement some methods that are public for use by the other classes in the library but not outwardly visible. Basically, I want to create something similar to Apple's "private" API calls.
I'm ok with someone being able to call these methods given that they discover their name, but I just want to mask them from the header file that's packaged with the library so that XCode doesn't give them the option to call those methods by default, possibly throwing a warning.
Any idea how this can be accomplished?
One idea is the following -
You can define the "private" methods of your class in a separate category in a separate .h file. For example, you could have class A looking like the following:
A.h
#interface A : NSObject {
}
- (void) foo; //public method
#end
Now the private methods of A can be declared in a different file:
A+Internal.h
#interface A (Internal)
- (void) bar; //private method
#end
The implementation file of A (A.m) can have implementations for both sets of methods.
In your static library, you do not publish the header files with "+Internal" in the name. Users of your library will only see methods in A.h, but classes inside your library can use both.
You can declare your "private" methods in a category #interface MyClass(PrivateMethods)or a class extension #interface MyClass() at the top of the .m file or in its own private header file.
From Extensions:
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class.
It is common for a class to have a publicly declared API and to then have additional methods declared privately for use solely by the class or the framework within which the class resides. You can declare such methods in a category (or in more than one category) in a private header file or implementation file as mentioned above. This works, but the compiler cannot verify that all declared methods are implemented.
Class extensions allow you to declare additional required methods for a class in locations other than within the primary class #interface block.
See also:
Best way to define private methods for a class in Objective-C

objective-c private versus public methods and declaration in header or not?

What is the best practice approach to private methods in objective-c. That is a method that's only going to be used the class as a helper method.
In particular what's not clear to me is:
Is there a need to have the method specified in the header file as private at all? i.e. why not just leave it out of the header file, and
If you can leave it out of the header file, then what is the point of having private methods?
Or is it the case in objective-c there is no such thing as real private methods, in which case is it better just to specify everything in the header file and no bother marking the private at all?
thanks
There is no need to specify the method in the public header file. You may want a "private" header file for use by other classes in your module, if the classes in your module are supposed to be "friends". You could even have a "protected" header file, as Apple does with UIGestureRecognizerSubclass.h for example. It's all just convention, though, nothing supported by the language itself.
A private method in Objective-C is just one that is not publicly documented; any method can still be called from anywhere, as long as the caller knows the name of it in order to create the appropriate selector. The advantage of not publicly documenting a method is that you are free to change or remove it without worrying about backwards compatibility. Leaving them out of the header file is one way of not publicly documenting them.
What you probably want to use is called "Class Extensions". They look similar, but shouldn't be confused with Categories. This will allow you to declare private methods in your .m file, and you'll get all the nice IDE corrections and suggestions.
Here's a decent article on it
And a related SO question
Best practice (and is even a compiler option to check) is that ALL methods be declared one way or the other. To 'hide' helper methods from prying eyes, declare it as such in the implementation .m file, as in:
#import Client;
#interface myClass (Private)
- (void) privateMethod;
- (float) bankAccountBalanceForClient:(Client *)client;
#end
#implementation myClass
- (void) privateMethod;
{
//foo here
}
and so on. the private methods are a Category called Private of myClass methods. This category can be declared anywhere, even in a master .h file called private methods, although that would be a maintenance nightmare.
So, using the public .h file for public methods, and the .m file to declare private methods, you have all your methods declared somewhere. I use this compiler option to ensure and force it, so that any method used is actually declared somewhere (or I get a syntax error) and thus I dont get any runtime crashes due to method not found.