Can I force protocol conformation in Swift? - ios

I'd like to do this:
UIView <UITextFieldDelegate>*
in swift.
Making an object that subclasses UIView also conform to the UITextFieldDelegate protocol.

You can express (id <UITextFieldDelegate, UIScrollViewDelegate>) using Protocol Composition
but not (UIView<UITextFieldDelegate> *). except for class definition.
// Obj-C
- (void)methodName:(id <UITextFieldDelegate, UIScrollViewDelegate>)arg { ... }
// Swift
func methodName(arg:protocol<UITextFieldDelegate, UIScrollViewDelegate>!) { ... }
Actually, an Obj-C method declared as - (void)methodName((UIView<UITextFieldDelegate> *))arg;, when it's bridged to Swift, you can call with any UIView instance.
EDIT:
After a little research, it seems you can declare your func like this
func myFunc<T:UIView where T:UITextFieldDelegate>(view:T) { ... }

Make a sub class of UIView and let the SubClassedView conforms to UITextFieldDelegate
In traditional way
#interface SubClassedView:UIView <UITextFieldDelegate>
#end
in swift
class SubClassedView:UIView, UITextFieldDelegate {
}

Related

Override property with different type

I want to implement the approach used by UITableView.
I have subclass UITableView with my own class FloatingTableView I want to override the delegate of UITableView which is UITableViewDelegate with my delegate of type FloatingTableViewDelegate just the way UITableView inherit from UIScrollView and override the UIScrollViewDelegate with UITableViewDelegate both class have same property with name delegate but have different types.
I have also tried to inherit my protocol with UITableViewDelegate
But when i try to create property with name delegate of type FloatingTableViewDelegate I get this error..
Property 'delegate' with type 'MyTableViewDelegate?' cannot override a
property with type 'UITableViewDelegate?'
Here is my sample code.
protocol MyTableViewDelegate: UITableViewDelegate {
func isDemoDelegateMethod()
}
class MyTableView: UITableView {
weak var delegate: MyTableViewDelegate?
}
The way it works for Objective C is because of the dynamic nature of the language. You can redeclare the type of super class and instead of synthesizing the property you would make it a dynamic type, which would let you redeclare it.
#protocol MyTableViewDelegate<UITableViewDelegate>
- (void)demoDelegateMethod;
#end
#interface WrapperTableView: UITableView
#property (nonatomic, weak, nullable) id <MyTableViewDelegate> delegate;
#end
#implementation WrapperTableView
#dynamic delegate;
#end
But, I doubt this would be possible with Swift, since, you are changing the type completely. It is because of Swift being strong static language.
Answer Edited
I got your approach. I write above approach in Objective-C and then inherit this class in Swift.
So if I have to override SuperClass property with different type I need to create a wrapper class in Objective-C inherit from desired SuperClass and then finally instead of inheriting directly from desired super class I should inherit from the newly created WrapperClass which is written in Objective-C
class MyTableView: WrapperTableView {
//Now Here the delegate object is of type MyTableViewDelegate
}
This approach is far better then
class MyTableView: UITableView {
private var myDelegate: MyTableViewDelegate?
override var delegate: UITableViewDelegate {
set{
myDelegate = newValue
}
get{
return myDelegate
}
}
}

How define a Type like `UIView<UITableViewDelegate>`(oc code) in swift?

An object of UIView or subclass of UIView and comforms to UITableViewDelegate protocol.
I need a generic type rather than a spesific type. So that developer who use it can define a freely. The oc code we can do like this:
#property (strong) UIView<SomeDelegate> *contentView;
I am thinking you are just looking for something like this
class MyView : UIView, UITableViewDelegate {
}
You will most likely have to add UITableViewDatasource protocol as well
Best practice you can use extension method for Current Class along with delegate or datasource:
class MyView : UIView {
}
extension MyView: UITableViewDelegate,UITableViewDataSource
{
}

Re-use function on every UIVIewController

I have a function that use very common on every UIViewController
func backPreviousScreen() {
self.navigationController?.popViewControllerAnimated(true)
}
Is anyway that I don't have to write detail that function above on each UIViewController ?, just need some method like I can inherit it, and use it in all UIViewController ?
You can create a protocol and add extension to it:
protocol Dismissable {
}
extension Dismissable where Self: UIViewController {
func backPreviousScreen() {
self.navigationController?.popViewControllerAnimated(true)
}
}
Now just mark the view controller class with this protocol and you are ready to go:
class MyViewController: UIViewController, Dismissable {
}
Create a BaseViewController with the method in it, then all of your viewcontrollers can inherit from it, thus all having the function
Instead of create base class method, Create a UINavigationController Extension. Which is you can use any where in your application.
import UIKit
import Foundation
extension UINavigationController
{
func backPreviousScreen (){
self.popViewControllerAnimated(true)
}
}
Use as follow self.navigationController.backPreviousScreen()
The idea of using a protocol is good, but i would recommend you to just create a class called BaseViewController that extends UIViewController like this
#interface BaseViewController : UIViewController
-(void) backPreviousScreen;
Then you can use it in any other controller like this
#import "BaseViewController.h"
#interface LoginViewController : BaseViewController
This was you can put functions, objects and everything you want and just call
[super backPreviousScreen];
from any of your subclasses
I recommend using this method and not the protocol because this way you can even create outlets easily since the storyboard and nibs recognise the base class and let you to create outlets that you can later access as well using
[super.someTextField setText:#"Some Text"];

Swift: Override Objective-c extension (anonymous) properties from subclass

I've spent quite a bit of time figuring this out..and haven't found any success.
Put simply, I need a swift subclass of an objective c class to be able to override a certain property declared in the .m file inside of an extension. How would I do this? Essentially the property needs to be replaced with a custom subclass.
#interface SomeClass : NSObject
{
}
#end
//SomeClass.m
#interface SomeClass ()
#property (nonatomic, strong) UIScrollView scrollView;
#end
//Swift class
class NewClass: SomeClass {
let scrollViewSubclass = MyScrollView()
override var scrollView: UIScrollView! {
return scrollViewSubclass
}
}
Something like that.. just not sure how to do it. I can't even override scrollView because the swift subclass doesn't know it exists!

Calling a Method on an Objective-C Delegate from Swift

I'm writing some Swift classes that build upon functionality in our objective-c app. I have a objective-c class with a delegate that conforms to a protocol. I'm trying to call a method on that delegate from inside of a Swift class I'm simplified it down to this.
FredTestProtocol.h:
#protocol FredTestProtocol
- (void) dumbMethod;
#end
FredTestClass.h:
#import <Foundation/Foundation.h>
#import "FredTestProtocol.h"
#interface FredTestClass : NSObject <FredTestProtocol>
#property (nonatomic, weak) NSObject <FredTestProtocol> *delegate;
#end
FredTestClass.m:
#import "FredTestClass.h"
#implementation FredTestClass
- (void) dumbMethod
{
NSLog(#"Boy, this is a dumb method");
}
#end
FredSwiftClass.swift
import Foundation
class FredSwiftClass {
func test()
{
let ocObject = FredTestClass()
ocObject.delegate.dumbMethod() // Error occurs here.
}
}
The indicated line produces the error "'NSObject' does not have a method named 'dumbMethod'" I've tried a lot of ways to eliminate the error, to no avail. I'm sure I'm missing something really fundamental. Can someone tell me how I should go about calling the delegate method from Swift?
When Swift examines the property delegate it simply sees that is is an NSObject and the fact that you have noted that it implements a protocol is ignored. I can't find any specific documentation as to why this is the case.
You can address this in a couple of ways.
First, you can redefine your delegate property to use class anonymity, then Swift will just see it as some object that implements the protocol -
FredTestClass.h
#import <Foundation/Foundation.h>
#import "FredTestProtocol.h"
#interface FredTestClass : NSObject <FredTestProtocol>
#property id<FredTestProtocol> delegate;
#end
Then your Swift code will compile as written.
or you can leave your delegate definition as is and tell Swift that you want to access the delegate as an instance of an object that implements the protocol via downcast -
FredTestSwift.swift
import Foundation
class FredSwiftClass {
func test()
{
let ocObject = FredTestClass()
let theDelegate=ocObject.delegate as! FredTestProtocol
theDelegate.dumbMethod()
}
}
Pretty sure I've got it.
func test()
{
let ocObject = FredTestClass()
if let myDelegate = ocObject.delegate as? FredTestProtocol
{
myDelegate.dumbMethod()
}
}

Resources