UIPickerView + TableViewCell + delegates and datasource - xcode

I have Table view Controller and separate class which handles for me tableviewcell. Inside the tableview cell I have pickerview.
How to implement delegate and datasource for pickerview which is in tableCell class but my delegate functions in tableview controller?

For Swift:
Create outlet for UIPickerView in custom table view class:
class MyTableViewCell: UITableViewCell, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet var myPickerView: UIPickerView!
}
Add delegate and datasource in "cellForRowAtIndexPath" in ViewController:
class myViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITableViewDelegate, UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell") as! MyTableViewCell
cell.myPickerView.dataSource = self
cell.myPickerView.delegate = self
return cell
}
}

You could have your tableView controller set a property on the tableview cells as they are created indicating that it is the delegate and datasource.
On the tableviewcell class you created just add a property that is an instance of you tableview controller. Like
#property (nonatomic, retain) MyTableViewController * pickerDelegate;
Then in your cellForRowAtIndexPath you can set that property to self
cell.pickerDelegate = self;
You might need to also set some sort extra property like a tag to distinguish between each cell. I would think another property on the tableviewcell like an NSIndexPath would do.

Related

Drag - connect an UISwitch to an IBOutlet on a delegate class

My goal is to enable/disable the editing of a UITextField with a UISwitch using delegates. This is the delegate class:
import Foundation
import UIKit
class SwitchedTextFieldDelegate : NSObject, UITextFieldDelegate{
#IBOutlet weak var switchText : UISwitch!
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
//Here I intended to read the UISwitch state
print("Can't touch this")
return false
}
}
I've tried to drag-connect the IBOutlet to the storyboard, but it is not possible. I can do it on the main view controller, which inherits UIViewController. I've already learned that multiple inheritance is not possible in Swift. How would you solve this? I'll try using an IBAction instead.
In your main view controller drag IBOutlet of a UITextField and UISwitch. Then confirm the UITextField Delegate. Now implement the UITextField Delegate method Like this:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if switchText.on{
return true
}else{
return false
}
}
For better understanding I have shared my ViewController screen shot.Here FirstViewController is just like your MainViewController. Hope this will help you.

getting the index path of a cell inside UITableViewCell in swift

could anyone tell me how to get the index of a cell inside its class which is uitableViewCell more specifically , inside an action function of UISwitch .
I did the following..
var cell = sender.superview?.superview as UITableViewCell
var table: UITableView = cell.superview as UITableView
let indexPath = table.indexPathForCell(cell)
but then it crashes.
what is the solution ?
Try this:
Assuming you have a UISwitch *cellSwitch object in cell custom class
In cellForRowAtIndexPath:
cell.cellSwitch.tag = indexPath.row
In IBAction for this switch:
let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
You don't want to know the index path of the cell inside of the cell. The index path is an implementation detail of the UITableViewController. The cell should be an independent object.
What you really want to do is to assign an action to run when your switch is changed.
class MySwitchCell: UITableViewCell {
#IBOutlet weak var switchCellLabel: UILabel!
#IBOutlet weak var mySwitch: UISwitch!
//Declare an action to be run
var action: ((sender: UISwitch) -> Void)?
//then run it
#IBAction func switchAction(sender: UISwitch) {
action?(sender: sender)
}
}
Then give the action something to do when you configure the cell.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SwitchCell", forIndexPath: indexPath) as! MySwitchCell
cell.switchCellLabel.text = items[indexPath.row]
cell.mySwitch.on = NSUserDefaults.standardUserDefaults().boolForKey(items[indexPath.row])
cell.action = { [weak self] sender in
if let tableViewController = self {
NSUserDefaults.standardUserDefaults().setBool(sender.on, forKey: tableViewController.items[indexPath.row]) }
}
return cell
}
For example this one sets a bool in the NSUserDefaults based on the state of that switch.
You can checkout the whole sample project from https://github.com/regnerjr/SimpleCellSwitchAction

Nil inherited outlet

I've defined a base class which has an UITableView outlet.
class BaseController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
...
Then I've inherited the class as follows:
class SubViewController: BaseController {
override func viewDidLoad() {
tableView.rowHeight = screenHeigth / CGFloat(textArray.count)
But the tableView is nil, I've just recently started programming in swift, is it possible to inherit an outlet? If so, how should I do it?
I'm currently using Xcode 6.4
You can inherit an outlet. In your storyboard (assumption), the view controller class name should be set to the name of your subclass. You can then connect up the table view to the outlet in the storyboard.

UITableView crashes if loaded from ContainerView

I've a big big problem related with a tableview (with a prototype cell made in IB) being loaded in a Container View. It loads perfectly, but when I try to tap or scroll over it just crashes with
respondsToSelector:]: message sent to deallocated instance 0x79a96e20
If I load the ViewController where the tableview is (without being embedded in a container view) it just works, which makes me think that has something to do with tableview being unallocated after parent viewcontroller finishes its loading process.
I'm pretty new with this and it's making me mad!!
Thanks for your help.
(THE VIEWCONTROLLER WHICH FILLS THE CONTAINERVIEW)
class cgGameViewerController: UIViewController {
#IBOutlet var cgGame:UIView; //Connected to IB ContainerView
override func viewDidLoad() {
var cgGameController=self.storyboard.instantiateViewControllerWithIdentifier("myIBviewController") as cgGameViewController;
self.cgGame.addSubview(cgGameController.view);
super.viewDidLoad()
}
}
(THE VIEWCONTROLLER WHICH IS LOADED IN A CONTAINERVIEW. In IB, UITableView delegate and datasource, is attached to the viewcontroller)
class cgGameViewController: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate,UITableViewDelegate,UITableViewDataSource {
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return 5;
}
func tableView(tableView:UITableView!, cellForRowAtIndexPath indexPath:NSIndexPath!) -> UITableViewCell! {
var myCell:UITableViewCell=tableView.dequeueReusableCellWithIdentifier("myCellInIB", forIndexPath: indexPath) as UITableViewCell;
return myCell;
}
}

UICollectionView inside UIView

I am trying to implement a UICollectionView inside a UIView, but I cant find out how to do it. There is a lot of tutorials on how to use UICollectionView with a UICollectionViewController, but not how to implement one in a regular View.
How do you do that?
1) Drag a UICollectionView into your UIView and size it appropriately.
2) Create a property which is also an IBOutlet in your .h file for the collection view:
#property (nonatomic, retain) IBOutlet UICollectionView *myCollectionView;
3) Again in your .h file declare your delegates, so now your .h should look somethng like this:
#interface UtaQuickView : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate> {
}
#property (nonatomic, retain) IBOutlet UICollectionView *myCollectionView;
4) Connect your myCollectionView IBOutlet in your storyboard.
5) (optional) If you're targeting anything older than iOS6 synthesize your myCollectionView property. If you're targeting iOS6, it will auto-synthesize it for you. This goes for all properties, not just UICollectionViews. So in iOS6, you don't need to #synthesize myCollectionView = _myCollectionView at all. You can just use _mycollectionview wherever you need to access the property.
6) In your .m file viewDidLoad, set your delegate and dataSource.
_myCollectionView.delegate = self;
_myCollectionView.dataSource = self;
7) Implement the required dataSource methods:
#pragma mark - UICollectionView DataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
From there you can implement as many or as little of the UICollectionViewDelegate methods as you need. However, 2 are required according to the documentation:
#pragma mark - UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
It's important to note that you can substitute <UICollectionViewDelegateFlowLayout> for <UICollectionViewDelegate> and still have access to all of the methods in <UICollectionViewDelegate> because <UICollectionViewDelegateFlowLayout> is a subclass of <UICollectionViewDelegate>.
UICollectionViewDataSource Protocol Documentation
UICollectionViewDelegate Protocol Documentation
And the Swift version
Drag a UICollectionView into your UIView and size it appropriately.
Modify your UIViewController to extend UICollectionViewDataSource and UICollectionViewDelegate
Implement the required functions
Control-Drag from your storyboard to the class to create an outlet 'collectionView'
In the viewDidLoad() wire up the delegate and datasource to self
collectionView.delegate = self and collectionView.dataSource = self
It should end up looking like this:
class CustomerViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate
{
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
collectionView.delegate = self
collectionView.dataSource = self
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
}
func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
}
func collectionView(collectionView: UICollectionView, didEndDisplayingSupplementaryView view: UICollectionReusableView, forElementOfKind elementKind: String, atIndexPath indexPath: NSIndexPath) {
}
}
Drag a UICollectionView into your UIView and size it appropriately.
Create a property which is also an IBOutlet in your .h file for the collection view:
#property (nonatomic, retain) IBOutlet UICollectionView *myCollectionView;
in UIView first you need to declare your UICollectionView cell in -(void)awakeFromNib
[myCollectionView registerNib:[UINib nibWithNibName:#"nib file of collectionView cell" bundle:nil] forCellWithReuseIdentifier:#"identifier"];
then
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
custom class *cell1=[collectionView dequeueReusableCellWithReuseIdentifier:#"identifier" forIndexPath:indexPath];
return cell1;
}
Drag uiviewcontroller to the stroryboard.
Create the new class file for the new uiviewcontoller
Set the newly created class to our viewcontroller. And add protocol methods to the .h file. -UICollectionViewDelegate,UICollectionViewDataSource
Drag uicollectionview to the viewcontroller, by default there will be a uicollectionviewcell with the collectionview.
Create new class for the cell customisation as the subclass of the uicollectionviewcell and set the class to the cell in the identity inspector. Also set reuse identifier in the attributes inspector, the name we should specify to identify the uicollectionviewcell. Say cell here.
Drag and drop an imageview(can be anything as your wish) inside the uicollectionviewcell, size it to fit within.
Set an image with the imageview(this image will be shown repeatedly with the collectionview).
Set the delegate and datasource with the uicollectionview to the corresponding viewcontroller.
Set datasource methods - numberOfItemsInSection and cellForItemAtIndexPath.
Return the required cell count with the numberOfItemsInSection method. Say 10 here.
Return the cell to display with the cellForItemAtIndexPath.
NSString * identifier = #"cell";
CollectionViewCellForDay * cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
return cell;
By now, you should be able to have a visual of a 10 cell collection view :)

Resources