Swift protocol nested in a class - swift

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.

Related

How can my Protocol oriented to specify ViewModel?

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.

Two ways of implement Delegation in Swift, what is the difference?

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
}

Argument of `#selector` does not refer to an initializer or method

I'm trying to perform a protocol extension method in the background:
performSelectorInBackground(#selector(retrieveCategories()), withObject: nil)
However I get the below error message:
Argument of `#selector` does not refer to an initializer or method
Here is my protocol declaration:
#objc protocol DataRetrievalOperations {
optional func retrieveCategories()
...
}
And my extension:
extension DataRetrievalOperations {
func retrieveCategories() {
...
}
}
How can I achieve this?
Try this:
#selector(DataRetrievalOperations.retrieveCategories)
With omitting class (or protocol) name in #selector(...) notation, Swift assumes the enclosing class, which may be a ViewController, I guess.
One more issue:
It seems Swift cannot implement #objc protocol methods with default implementation in protocol extension.
(I think I have heard something about this, but I couldn't find any articles for now.)
You may need to implement it in your own class's extension or find another way.
extension CategoriesViewController {
func retrieveCategories() {
//...
}
}
I need to add that this will solve the first issue and #selector(retrieveCategories) will work.
You can't add an #Objc method in a Protocol Extension. You need to extend the Class which inherits NSObject and that Protocol and add the objc function there like so:
#objc protocol DataRetrievalOperations {
optional func retrieveCategories()
}
class aClass: NSObject, DataRetrievalOperations {
func method() {
performSelectorInBackground(#selector(retrieveCategories), withObject: nil)
}
}
extension aClass {
#objc func retrieveCategories(){
}
}
This will work.

Declare variable of type UIView conforming to a protocol in Swift 2

I need to declare a variable of type UIView which also conforms to MyProtocol:
protocol MyProtocol: class {
func foobar()
}
class MyClass {
var myView: UIView<MyProtocol>! // Error: Cannot specialize non-generic type 'UIView'
}
However I get the compiler error: Cannot specialize non-generic type 'UIView'.
I need to access methods on the variable from UIView and MyProtocol.
What is the correct variable declaration to support these requirements?
If it makes any difference, only UIView subclasses will implement the protocol. Currently I add protocol conformance via extensions.
I found this answer: https://stackoverflow.com/a/25771265/233602 but it's not clear if that answer is still the best option going in when writing in Swift 2.
Make your class a generic class as follows,
protocol MyProtocol: class {
func foobar()
}
class MyClass<T:MyProtocol where T:UIView> {
var myView: T!
}
The error above says that UIView cannot specialise to protocol MyProtocol, so, the solution here would be to make your class a generic class which takes generic parameter which conforms to MyProtocol and is subclass of UIView.
Probably the best way to solve this is to use a protocol where all UIViews conform to:
protocol UIViewType {
var view: UIView { get }
}
extension UIView: UIViewType {
var view: UIView { return self }
}
// the variable
var myView: protocol<UIViewType, MyProtocol>
Use the view property to access UIView specific functionality.
Late to the party here, but SE-0156 (adopted by Swift 4) enables class and protocol composition in type declarations without requiring (resorting to?) generics.
protocol MyProtocol: class {
func foobar()
}
class MyClass {
var myView: (UIView & MyProtocol)!
}
If it makes any difference, only UIView subclasses will implement the
protocol.
It makes all the difference! Just do this:
protocol MyProtocol: UIView {
func foobar()
}
class MyClass {
var myView: MyProtocol!
}

Swift - implementing NSXMLParserDelegate

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
}
}