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
}
}
}
Related
Currently I am trying to convert Objective-C code to Swift, and facing some issue with delegate of id type.
Below is the code as following:
#property (weak, nonatomic) id <TestDelegate> delegate;
During initialization time, there is a controller being send and set as a delegate like this:
- (instancetype)initWithController:(id)controller {
self = [super init];
if (self) {
self.delegate = controller;
}
return self;
}
As you can notice, since the delegate here is an id type which can keep of any kind of reference, it is storing the reference of the controller for delegate, and the controller that is being passed is conforming the protocol of "TestDelegate". However, I am curious how can you achieve this in swift?
Thanks
I think the id type maps to "Any". This is dangerous, and should probably be replaced with actual type in swift:
weak var delegate: TestDelegate?
init(delegate: TestDelegate) {
self.delegate = delegate
}
If dealing with reference types, you’d generally define your protocol as a class protocol:
protocol TestDelegate: class {
...
}
And then make your delegate property weak:
class Foo {
weak var delegate: TestDelegate?
init(delegate: TestDelegate) {
self.delegate = delegate
}
}
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
{
}
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!
I have a superclass A that has a BaseModalViewControllerDelegate protocol and a retain property for the id<BaseModalViewControllerDelegate> delegate.
I also have class B, subclass of A, that has a ModalLoginDelegate protocol and a retain property for the id<ModalLoginDelegate> delegate
Now, I set as setter method for B class delegate this method:
-(void)setDelegate: (id<ModalLoginDelegate>)delegate
{
_delegate = delegate;
[super setDelegate: (id<BaseModalViewControllerDelegate>)delegate;
}
So, there is the RootViewController that implements both protocol, but it inits only B class and it set itself as delegate only for B class because it doesn't know that B class is a subclass of A.
Do you think that this is a correct way to set RootVC as delegate for both protocol? Thanks
ADDING
Setting the protocol of B class as inherited from A class:
#protocol ModalLoginDelegate <BaseModalDelegate>
// delegate method of subclass
#end
Now, my RootVC has not to set itself as delegate of BaseModalViewController. But now, when in my B class I want to call the delegate method of the superclass I'm doing this
if (self.loginDelegate)
{
[self.loginDelegate baseModalViewController: self willDismiss: YES];
}
I think that this is not a very clean way, so I created a public method in the superclass -(void)pressedCloseButton; that it will do this
-(void)pressedCloseButton
{
if (self.delegate)
{
[self.delegate baseModalViewController: self willDismiss: YES];
}
}
And in the subclass:
-(IBAction)closeBtnPressed: (id)sender
{
[super pressedCloseButton];
}
Do you think is right?
A better design is to implement a separate delegate property for your subclass, say loginDelegate. It isn't very good OO design to change the type of a property in a subclass. Most OO languages won't even allow it.
This also ensures that the consuming class is "aware" that there are two separate delegate protocols involved.
RootVC will need to set itself as both delegates if it needs to implement both protocols. You can't expect the class not to know which delegate protocols it needs to implement. If RootVC thinks it is only dealing with the base class then it won't set loginDelegate and won't implement the methods in that protocol.
I don't disagree with Paulw11's answer here at all, but it interesting to note that Apple themselves do this.
example. UIScrollView has a delegate property
#property (weak, nonatomic) id <UIScrollViewDelegate> delegate;
and a subclass, UITableView, has a delegate property
#property (weak, nonatomic) id <UITableViewDelegate> delegate;
When we declare a protocol in ObjC we usually have that protocol extend the < NSObject > protocol.
#protocol BaseModalViewControllerDelegate <NSObject>
-(void)doSomething;
-(NSString *)titleForThing;
#end
Now this protocol above has not only the methods prototyped here but also those in the < NSObject > protocol. Its is very much like this protocol is a 'subclass' of the other protocol, inherits all its stuff too.
If you did this with your second protocol
#protocol ModalLoginDelegate <BaseModalViewControllerDelegate>
-(void)doAnotherThing;
-(NSString *)titleForTheOtherThing;
#end
then what you've done here would be absolutely in line with what Apple have done with UITableView and UIScrollView, because a pointer of type id< ModalLoginDelegate > is always also an object of type id< BaseModalViewControllerDelegate > , just as a UIButton* will always be able to be passed in as a UIView* ...
But without doing this there is a fundamental problem in your
-(void)setDelegate:(id<ModalLoginDelegate>)delegate
method there, because you are assuming this object complies with the BaseModalViewControllerDelegate protocol when the only thing you know for sure is that it complies with the ModalLoginDelegate protocol. Some inherited method may call on self.delegate with a BaseModalViewControllerDelegate method which self.delegate does not respond to..
I hope this helps :)
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 {
}