Say for example you have a protocol in Swift:
protocol WeatherServiceDelegate: class {
func didCompleteRequest(result: String)
}
Two ways of implementing them:
Way 1: Via class inheritance
class ViewController: UIViewController, WeatherServiceDelegate {
....
}
Way 2: Via extension
However, Swift does provide a keyword extension which can be used to implement the protocol methods
extension ViewController: WeatherServiceDelegate{
func didCompleteRequest(result: String){
print(result)
}
}
Is there any difference on those two methods?
Per Apple's guide:
Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling).
So it appears in your case there is little difference except in how you want to arrange your code.
Well! There's no difference at runtime. But when adding protocol conformance to a model, prefer adding a separate extension for the protocol methods. This keeps the related methods grouped together with the protocol and can simplify instructions to add a protocol to a class with its associated methods.
Preferred:
class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
Not Preferred:
class MyViewController:UIViewController,UITableViewDataSource,UIScrollViewDelegate {
// all methods
}
Related
I have a problem from Protocol oriented ViewModels.
I have two very similar pages,so i made a baseController and baseViewModel to put shared properties and methods. And made two other controllers and viewModels for two pages.
And I made a protocol to define the properties and methods.
My baseController has var viewModel: BaseViewModelProtocol .
But my other two controller cannot use the properties and methods from their viewModel, it's says
Value of type 'BaseViewModelProtocol?' has no member ''
ViewModel1 is for Controller1, ViewModel2 is for Controller2, here is my example
protocol BaseViewModelProtocol {
var name: String { get }
func reset()
}
class BaseViewModel: BaseViewModelProtocol {
func reset() { }
}
class ViewModel1: BaseViewModel {
var score: Int = 0
func someMethods() {}
}
class ViewModel2: BaseViewModel {
var money: Int = 1000
func something() {
print("something")
}
}
class BaseViewController: UIViewController {
var viewModel: BaseViewModelProtocol?
init(viewModel: BaseViewModelProtocol) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
}
class ViewController1: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(viewModel?.score) //it is error!!!!
}
}
When i init the Controller, i Cannot use any properties and methods from ViewModel2, and the same like controller1.
class ViewController2: BaseOrderViewController {
override func viewDidLoad() {
super.viewDidLoad()
viewModel?.something(). //it is error!!!!
}
}
how to my protocol oriented viewModel?
After reading your post I feel like there is too many things that should be addressed here.
You are trying to ask something before understanding important characteristics of the Object Oriented Programmation paradigm. I recommend you to try and search information about class abstraction, composition vs inheritance and specificaly how to use the protocols in Swift.
Maybe you could start with https://cocoacasts.com/how-to-create-an-abstract-class-in-swift.
Even so, i am going to try to point out some issues in your code.
Seems like you tried to "hide" your source code by changing your classes and properties' names. The way it's done makes it harder to read, understand and introduces mistakes.
Inheriting from another class:
class ViewModel1: BaseViewModel
it's not the same as inheriting from a protocol:
class BaseViewModel: BaseViewModelProtocol
while the first one provides you a default implementation of a method that can be overrided, the second, doesn't. So it is mandatory to provide the implementation of the method in every class that inherits the protocol.
Note that the BaseViewController has a property with type BaseViewModelProtocol. That protocol doesn't have a method called "something" neither can inherit that function from another. It's within reason that the compiler shows the error.
If you want to use "something" from a Class that inherits BaseViewController, you have many ways. You could change the type of the viewModel in the BaseViewController to BaseViewModel after adding there an implementation of "something". You could also add the function to the protocol and make sure that it's implemented in all of the classes which inherit the protocol...
I hope I have helped you.
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.
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
I try to create myPet by inherit from two classes but error for example:
import UIKit
class SecondViewController: UIViewController, UITextFieldDelegate {
// No Error
}
Then the following classes were defined then create new class myPets which I like to inherit both Dog and Substance. But error: Multiple inheritance from classes 'Dog' and 'Substance'
class Dog:Animal {
func sound()->String {
return "Hong Hong"
}
}
class Substance {
func livingCompound()->String {
return "Consist of bio-molecule"
}
}
class myPets:Dog, Substance {
func itsAddress()->String {
// Error:Multiple inheritance from classes 'Dog' and 'Substance'
}
}
Swift does not support multiple inheritance, following Objective C in this. This is NOT inheritance from two classes:
class SecondViewController: UIViewController, UITextFieldDelegate
It is inheritance from one class UIViewController and adopting the UITextFieldDelegate protocol. Read about protocols at https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
I'm trying to have a class of mine implement NSXmlProtocolDelegate but the compiler fails indicating that the class does not conform to NSObjectProtocol.
Is it required that all of the functions from NSObjectProtocol be implemented, or can that be avoided?
class GeoRssParser : NSXMLParserDelegate
{
func parserDidStartDocument(parser : NSXMLParser)
{
}
}
Not much to see at this point - I got this far before the compiler started failing.
Yes, at least anything that isn't tagged as #optional. The easiest way to achieve this would be to simply make your class a subclass of NSObject, which already conforms to the NSObjectProtocol, and implements all its methods.
class GeoRssParser: NSObject, NSXMLParserDelegate {
func parserDidStartDocument(parser : NSXMLParser) {
// stuff
}
}