when and why would a class be a subclass of NSObject? - swift

In some tutorials, I've seen:
class MyClass: NSObject {
var a: String!
var b: String!
init(a: String, b: String) {
super.init()
self.a = a
self.b = b
}
}
I was under the impression that swift classes didn't need to subclass anything. Is there any reason why someone would want to subclass from NSObject ?

NSObject class is not so important. What really is important is the NSObject protocol, in Swift named NSObjectProtocol.
For example, most protocols in Cocoa/CocoaTouch inherit from NSObjectProtocol. That means that if you want to use such protocols (for example, to implement delegates), you have to implement all the methods from NSObjectProtocol. That's pretty hard but NSObject class implements them all for you so the easiest solution is to inherit from NSObject class.

When you don't subclass NSObject you lose all the cool stuff Selector that comes with it: performSelector, respondsToSelector etc...
Also - this way you can make sure your Swift code objects can interact with legacy Objective-C code.

Related

How to know this NSObject is class or protocol in swift?

In swift , super class and protocol is write together like this
Most of times ,this will not make misunderstanding , But because there is a NSObject class and a NSObject protocol with the same name, How to distinguish them?
And how the compiler know to use the NSObject class not the NSObject protocol?
And If I want to use the NSObject protocol not the NSObject class , how to write the class declaration?
The protocol is called NSObjectProtocol not NSObject which is a class. If you want something to conform to NSObjectProtocol exclusively use that:
protocol MyProtocol: NSObjectProtocol { }
On the other hand NSObject conforms to NSObjectProtocol. So in conclusion by inheriting a class from NSObject means it's refering to the NSObject class and (not the NSObject objective-c #protocol) ipso facto conforms it to NSObjectProtocol.
In Swift, NSObject protocol is imported as NSObjectProtocol so there is no naming conflict.
https://developer.apple.com/documentation/objectivec/1418956-nsobject?language=objc

Swift protocol nested in a class

I would like to nest a protocol in my class to implement the delegate pattern like so :
class MyViewController : UIViewController {
protocol Delegate {
func eventHappened()
}
var delegate:MyViewController.Delegate?
private func myFunc() {
delegate?.eventHappened()
}
}
But the compiler will not allow it :
Protocol 'Delegate' cannot be nested inside another declaration
I can easily make it work by declaring MyViewControllerDelegate outside of the class scope.
My question is why such a limitation ?
according to the swift documenation
Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support.
Given protocols are not on that list, it doesn't appear that it's currently supported.
It's possible they will add the feature at some point, (Swift was announced less than 2 years go after all). Any idea on why they won't or haven't would be speculation on my part.
this is my work around:
protocol MyViewControllerDelegate : class {
func eventHappened()
}
class MyViewController : UIViewController {
typealias Delegate = MyViewControllerDelegate
weak var delegate: Delegate?
private func myFunc() {
delegate?.eventHappened()
}
}
A separate problem with your class is that delegate does not have a concrete type. You can get away with declaring it a MyViewController.Delegate? because it is an optional type and can be .None. But that just makes your private myFunc dead code. Only enumerations, classes, and structures can conform to a protocol. Which of those three types is delegate?
That said, this is not the cause of your problem. When I make a real type for delegate and make it conform to the Delegate protocol, I still get the same error.
class MyViewController: UIViewController {
protocol Delegate {
func eventHappened()
}
class Classy: Delegate {
func eventHappened() {
print("eventHappened")
}
}
var delegate: Classy? = Classy()
func myFunc() {
delegate?.eventHappened()
}
}
As an esoteric exercise this might be interesting in pushing the bounds of what a class might do but no one should every try to declare a protocol inside of a class. Protocols are all about type composition and collections. There is no code reuse scenario when you are limited to being in the same outer class.

swift error multiple inheritance from classes NSObject and NSCoder

I have a class called Diary which implements NScoder and has a member which is an array of another class called DiaryEntry
Here is my Diary class
import Foundation
class Diary: NSObject,NSCoder
{
var dia=[DiaryEntry]()
override init()
{
super.init()
}
func setDiary(ent:DiaryEntry)
{
if(dia.count==0)
{
self.dia.append(ent)
}
else {
for entrie in dia
{
if(entrie==ent)
{
entrie.text+="\n"
entrie.text+=ent.text
break
}
else {
self.dia.append(ent)
}
}
}
}
required init(coder decoder: NSCoder) {
self.dia = decoder.decodeObjectForKey("dia") as [DiaryEntry]
super.init()
}
func encodeWithCoder(encoder: NSCoder) {
encoder.encodeObject(dia, forKey: "dia")
}
}
Swift does not support multiple inheritance. NSCoder already inherits NSObject so there is no reason for your diary class to try and inherit both (which, again, is not possible).
This is an easy mistake to make; you accidentally used NSCoder instead of NSCoding. -er vs -ing
For an explanation;
NSCoder is a class, while NSCoding is a protocol. Placing another class after NSObject makes the compiler think you're asking for multiple class inheritance. Swift doesn't currently (as of 5.x) support multiple inheritance.
In Swift, you 'conform' to protocols, therefore bypassing the multiple v-table issue (and all the complexity and problems it causes) by basically merging (gross simplification) the protocol with the conforming class. You can therefore conform to as many protocols as you like (within compiler imposed limitations of course).
Long story short, you want your class to inherit from NSObject and conform to NSCoding, which is a protocol, and not inherit from both NSObject and NSCoder (which is what you were accidentally telling the compiler to do).
the protocol's name is: NSCoding no NSCoder

How to declare a swift class with a property that conforms to some protocol

Is it possible for swift to have a ViewController class, initialized from xib, has a property that is also a subclass of UIViewController and conforms to some protocol?
protocol SomeProtocol {
// Some methods
}
class ViewController: UIViewController {
// contentView is initialized from xib
#IBOutlet weak var contentView: UIView!
// I'd like to declare anotherViewController both conforms to 'SomeProtocol'
// and a subclass of UIViewController
var anotherViewController: UIViewController!
...
}
When I declare ViewController as an generic class, say class ViewController<T: UIViewController, SomeProtocol>, I get an error :
"Variable in a generic class cannot be presented in Objective-C"
So how can I fulfil it if I cannot use generic class?
Please forgive me if I misunderstood your problem, but I think what you want to do is declare a new type that inherits from UIViewController and conforms to SomeProtocol, like so:
protocol SomeProtocol { }
class VCWithSomeProtocol: UIViewController, SomeProtocol {
}
class ViewController: UIViewController {
var anotherViewController: VCWithSomeProtocol!
}
So I hope I am not misunderstanding the question as well, but it sounds like you may want a multiple-inheritance object level mixin such as:
let myVC: ViewController, SomeProtocol
Unfortunately, Swift does not support this. However, there is a somewhat awkward work-around that may serve your purposes.
struct VCWithSomeProtocol {
let protocol: SomeProtocol
let viewController: UIViewController
init<T: UIViewController>(vc: T) where T: SomeProtocol {
self.protocol = vc
self.viewController = vc
}
}
Then, anywhere you need to do anything that UIViewController has, you would access the .viewController aspect of the struct and anything you need the protocol aspect, you would reference the .protocol.
For Instance:
class SomeClass {
let mySpecialViewController: VCWithSomeProtocol
init<T: UIViewController>(injectedViewController: T) where T: SomeProtocol {
self.mySpecialViewController = VCWithSomeProtocol(vc: injectedViewController)
}
}
Now anytime you need mySpecialViewController to do anything UIViewController related, you just reference mySpecialViewController.viewController and whenever you need it to do some protocol function, you reference mySpecialViewController.protocol.
Hopefully Swift 4 will allow us to declare an object with protocols attached to it in the future. But for now, this works.
Hope this helps!

Type constraint on AnyObject or Any (AnyObject or Any that conforms to a protocol)

I'm trying to convert my Objective-C code to swift.
In Objective-C I have the following protocol:
#protocol RWOverlaySelectionDelegate <NSObject>
-(void)areaSelected:(UIView *)view allPoints:(NSArray *)points;
#end
and following class has a weak property that reference the protocol (obviously it's defined as weak to prevent strong reference cycle).
#interface RWMapSelectionLayer : UIView
#property(weak, nonatomic) id <RWOverlaySelectionDelegate> delegate;
#end
Now the Swift equivalent:
the protocol:
protocol RWOverlaySelectionDelegate {
func areaSelected(view:UIView,points:CGPoint[])
}
and the class that has a property which conforms to that protocol:
class RWMapSelectionLayer:NSObject {
weak var delegate:RWOverlaySelectionDelegate?
}
But I'm getting 'weak' cannot be applied to non-class type 'RWOverlaySelectionDelegate' compile time error in this line : weak var delegate:RWOverlaySelectionDelegate?
Then I tried to convert my property to an AnyObject that conforms to RWOverlaySelectionDelegate using following syntax:
weak var delegate: AnyObject<RWOverlaySelectionDelegate>?
Now I'm interfering with Generics and compiler showing: Cannot specialize non-generic type 'AnyObject' error.
In another unsuccessful try I changed it to
weak var delegate: AnyObject:RWOverlaySelectionDelegate?
read it as "Delegate is on type AnyObject where AnyObject should conform to RWOverlaySelectionDelegate"
This is again incorrect because of two colons(:) in a single statement.
Would appreciate if someone can help me to enforce conformance to a protocol on AnyObject or Any
I have since found a better way of doing this in this answer.
Updated for recent Swift versions
As I mentioned in my comment on CjCoax's answer, prefixing the protocol with #objc prevents passing Swift object types (such as enums and structs) to delegate methods.
However, using : AnyObject will allow this behaviour while allowing the protocol to be used in a weak variable, though this method is not without its limitations. You can only make classes conform to any protocol that is marked with : AnyObject. I believe that this is a better trade-off than #objc provides.
protocol MyProtocol: AnyObject {
...
}
I believe the recommended solution would be a class-only protocol. From the Swift Programming Language protocol page:
You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject protocol to a protocol’s inheritance list.
So in your example, your protocol definition would look like:
protocol RWOverlaySelectionDelegate: AnyObject {
func areaSelected(view: UIView, points: NSArray)
}
With the addition of the AnyObject keyword, the compiler should no longer complain.
Since swift 4 instead of class we should use AnyObject. From the Swift Programming Language protocol page:
You can limit protocol adoption to class types (and not structures or
enumerations) by adding the AnyObject protocol to a protocol’s
inheritance list.
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
Found the solution:
I just need to declare my protocol as follow:
#objc protocol RWOverlaySelectionDelegate {
func areaSelected(view:UIView,points:NSArray)
}
and then the class just uses protocol name rather than an AnyObject that conforms to a protocol
class RWMapSelectionLayer:NSObject {
weak var delegate: RWOverlaySelectionDelegate?;
}
Protocol declaration which is #objc protocol RWOverlaySelectionDelegate require object of RWOverlaySelectionDelegate to be a class.
Here is the reference from The Swift Programing Language guide provided by apple
#objc protocols can be adopted only by classes