Is there a smart way to superclass both UITableviewDataSource and a UICollectionViewDatasource - ios

I would like to have 1 super class for both UITableviewDataSource and UICollectionViewDatasource. What is the right way to do it?

You can declare your own protocol and state that the new protocol conforms to UITableViewDataSource and UICollectionViewDataSource. Let's call it CombinedProtocol. Then anything that says it implements the CombinedProtocol will have to implement the usual table view and collection view methods.
#protocol CombinedProtocol <NSObject, UITableViewDataSource, UICollectionViewDataSource>
// add any additional methods if you want
#end

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

Why does UICollectionView conform to UICollectionViewDelegateFlowLayout by default?

I'm just confused with the following code that gets executed in a UICollectionViewController instantiated from a xib file:
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 1.0;
}
which is declared in the protocol UICollectionViewDelegateFlowLayout. However, there is nowhere in the UICollectionViewController showing that it would conform to this protocol, as declared in the UICollectionViewController:
NS_CLASS_AVAILABLE_IOS(6_0) #interface UICollectionViewController : UIViewController <UICollectionViewDelegate, UICollectionViewDataSource>
Can anyway explain why UICollectionViewController would conform to UICollectionViewDelegateFlowLayout?
By default, the class of a collection view's layout when dragged into a xib/storyboard is UICollectionViewFlowLayout, which is why by default the delegate methods for UICollectionViewDelegateFlowLayout are called. If you were to change the layout object's class in the xib/storyboard, none of the methods specific to UICollectionViewDelegateFlowLayout would be called.
Also, UICollectionViewController may privately conform to UICollectionViewDelegateFlowLayout, or it may not. It doesn't really matter because a class doesn't technically have to explicitly conform to a protocol in order to implement and respond to methods in that protocol.

Set superclass delegate from subclass setDelegate

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 :)

Accessing a TableView within a ViewController

I've got a ViewController that has a UITableView within it. When I'm watching tutorials people are using things like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _Title.count;
}
How am I able to generate the stubs without firstly creating the class with them in. When I made the class I selected it as a UIViewController. I've been playing around trying to auto generate the stubs but all to no avail.
Simply add the UITableViewDataSource (and most likely the UITableViewDelegate) to your UIViewController declaration. Example:
// MyViewController.h
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
// ...
#end
After that your implementation file MyViewcontroller.m should help you with the code completion.
One note: don't forget to set yourself as dataSource:
_tableview.dataSource = self;
If you added the tableview by code, you need to create a property (weak) in order to have a reference to your table view after adding it to your view controller's subview. If you add it by using interface builder, you need to create a iboutlet property that will allow you to "bind" your table view property with the xib/storyboard file representing your view controller. Alternatively, you can use UITableViewController as the parent class of your view controller. This class already has a property to access the table view in your view controller.
Tell your controller that you need to conform to the table view protocols and they will start to auto-complete when you try to type them in. You can check the docs of a protocol to find the available methods. Checking the UITableView docs would tell you about the relevant data source and delegate:
The data source must adopt the UITableViewDataSource protocol and the delegate must adopt the UITableViewDelegate protocol.
In your header file:
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
You have a couple of options.
You could make your class inherit from UITableViewController instead of UIViewController. This will give you a tableView so you don't need to make one.
Or...
Your UIViewController could implement the protocols UITableViewDataSource and UITableViewDelegate. Then set the dataSource and delegate properties of your table view to self (your view controller containing the table).
-First of all you may need to add datasource and delegate of UITableViewController in your UIViewController header file
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
and then implement the required and optional methods to populate the data in your _tableView.
Sample Code for TableView demonstration by Apple:
https://developer.apple.com/library/ios/samplecode/TableViewSuite/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007318

Resources