Moving/Deleting Diffable TableView Rows - swift

I am trying to update a tableView to UITableViewDiffableDataSource but I am having trouble with being able to delete/move the rows. With some help from a previous question, I have subclassed the dataSource and added the tableview overrides there. The rows will edit but when I leave and come back to the view they go back to the way they were as my data models in my VC are not updating with the edits. Can anyone help with this?
extension NSDiffableDataSourceSnapshot {
mutating func deleteItemsAndSections(_ items : [ItemIdentifierType]) {
self.deleteItems(items)
let emptySection = self.sectionIdentifiers.filter {
self.numberOfItems(inSection: $0) == 0
}
self.deleteSections(emptySection)
}
}
fileprivate class ListDrillDownDataSource: UITableViewDiffableDataSource<String, ListItem> {
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
guard editingStyle == .delete else { return }
// Delete the row from the data source
if let item = self.itemIdentifier(for: indexPath) {
var snapshot = self.snapshot()
snapshot.deleteItemsAndSections([item])
self.apply(snapshot, animatingDifferences: true)
}
}
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
}
Edit**
I have made some progress by adding a backingStore and I am closer to being able to update an existing cell. However, I ultimately just keep getting stuck in the same loop of errors.
I started by adding a backingStore property who's values are a custom ListItem class. The class is hashable with a UUID() as one of the properties.
class ListDrillDownTableViewController: UITableViewController {
fileprivate var dataSource: ListDrillDownDataSource!
fileprivate var currentSnapshot: ListDrillDownSnaphot?
var list: List = List(name: "Test List", listStyle: .preSetStyle[0], listItems: [], users: [])
var backingStore = [UUID: ListItem]()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = self.editButtonItem
self.dataSource = createDataSource()
updateUI(animated: false)
tableView.rowHeight = 65
}
Then I created a method to create the dataSource giving the cell provider the UUID to look up the listItem. I also updated the UI with the initial snapshot populating the UUIDs and the backingStore.
fileprivate func createDataSource() -> ListDrillDownDataSource {
let dataSource = ListDrillDownDataSource(tableView: tableView) { (tableView, indexPath, uuid) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "ListItemCell", for: indexPath) as! ListItemCell
guard let listItem = self.backingStore[uuid] else { return cell }
cell.titleLabel.text = listItem.title
if let cost = listItem.cost {
cell.costLabel.isHidden = false
cell.costLabel.text = (listItem.costString(cost: cost))
} else {
cell.costLabel.isHidden = true
}
if listItem.note == "" {
cell.noteIcon.isHidden = true
} else {
cell.noteIcon.isHidden = false
}
if listItem.askToReschedule && !listItem.hasRepeatInterval {
cell.repeatIcon.isHidden = false
cell.repeatIcon.image = UIImage(systemName: "plus.bubble")
} else if !listItem.askToReschedule && listItem.hasRepeatInterval {
cell.repeatIcon.isHidden = false
cell.repeatIcon.image = UIImage(systemName: "repeat")
} else {
cell.repeatIcon.isHidden = true
}
return cell
}
self.tableView.dataSource = dataSource
return dataSource
}
func updateUI(animated: Bool = true) {
var snapshot = ListDrillDownSnaphot()
snapshot.appendSections(["main"])
let uuids = self.list.listItems.map { _ in UUID() }
snapshot.appendItems(uuids)
for (uuid, listItem) in zip(uuids, list.listItems) {
self.backingStore[uuid] = listItem
}
self.dataSource.apply(snapshot, animatingDifferences: animated)
}
Finally, when the user taps a cell, makes there edits and taps done the view unwinds back to this controller and I attempt to update the dataSource in the unwind method. As it stands the app will create the first new cell but when a second is attempted it reloads the first row twice and as I keep adding it doubles the existing rows. I'm guessing because I'm appending the whole list over and over, but I can't figure out how to access JUST the appended uuid.
When I tap into an existing cell and edit the info it works, but if I go in again to the row and come out the cell goes back to it's original state. If I keep trying it bounces back and forth between the original state and the updated, almost like it is bouncing back and forth between snapshots?
#IBAction func unwindToListDrillDownTableView(_ unwindSegue: UIStoryboardSegue) {
// Verify the correct segue is being used.
guard unwindSegue.identifier == "DoneAddEditListItemUnwind" else { return }
let sourceViewController = unwindSegue.source as! ListItemDetailTableViewController
// Update the Lists categories with any changes.
self.list.listStyle?.categories = sourceViewController.currentCategories
// Verify a ListItem was returned.
if let listItem = sourceViewController.listItem {
// Check if ListItem is existing.
if let indexOfExistingListItem = list.listItems.firstIndex(of: listItem) {
// If existing, update the ListItem and then the view.
list.listItems[indexOfExistingListItem] = listItem
let uuid = self.dataSource.itemIdentifier(for: IndexPath(row: indexOfExistingListItem, section: 0))
let uuids = self.list.listItems.map { _ in UUID() }
var snapshot = self.dataSource.snapshot()
snapshot.reloadItems([uuid!])
for (uuid, listItem) in zip(uuids, list.listItems) {
self.backingStore[uuid] = listItem
}
self.dataSource.apply(snapshot, animatingDifferences: true)
} else {
// If new, add to listItems collection and update the view.
list.listItems.append(listItem)
if self.backingStore.keys.isEmpty {
updateUI()
} else {
var snapshot = self.dataSource.snapshot()
let uuids = self.list.listItems.map { _ in UUID() }
snapshot.reloadSections(["main"])
snapshot.appendItems(uuids)
for (uuid, listItem) in zip(uuids, list.listItems) {
self.backingStore[uuid] = listItem
}
self.dataSource.apply(snapshot, animatingDifferences: true)
}
}
}
}

Related

Constraints are broken after pushing VC again

My constraints are broke when I pop VC. I have table view, when I firstly push table view, constraints are work perfectly, but after poping and pushing again they are broke. First image are working good, but in second they are broke Maybe problem is in didSet, after breaking constraints xcode says to remove width, but ui will be bad
This is my cell code
var isIncoming: Bool! {
didSet {
bubbleBackgroundView.backgroundColor = isIncoming ? Constants.Color.inComingMessages : Constants.Color.outComingMessages
messageLabel.textColor = isIncoming ? .black : .white
if isIncoming {
bubbleBackgroundView.snp.makeConstraints { (make) in
make.leading.equalTo(16)
make.width.equalTo(180)
}
messageLabel.snp.makeConstraints { (make) in
make.leading.equalTo(16)
}
addSubview(inComingImgTail)
inComingImgTail.snp.makeConstraints { (make) in
make.trailing.equalTo(bubbleBackgroundView.snp.leading).offset(12)
make.top.equalTo(bubbleBackgroundView.snp.top).offset(1)
make.width.equalTo(15)
make.height.equalTo(36)
}
}
else if !isIncoming{
bubbleBackgroundView.snp.makeConstraints { (make) in
make.trailing.equalTo(self).offset(-16)
make.width.equalTo(180)
}
messageLabel.snp.makeConstraints { (make) in
make.leading.equalTo(16)
make.trailing.equalTo(-16)
}
addSubview(OutComingImgTail)
OutComingImgTail.snp.makeConstraints { (make) in
make.trailing.equalTo(bubbleBackgroundView.snp.trailing).offset(4)
make.top.equalTo(bubbleBackgroundView.snp.top).offset(1)
make.width.equalTo(15)
make.height.equalTo(36)
}
}
}
}
This is my dataSource and delegate code
extension ChatVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ChatVC.messagesList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MessagesCell.reuseIdentifier, for: indexPath) as! MessagesCell
let messages = ChatVC.messagesList[indexPath.row]
let sorted = ChatVC.messagesList.sorted { (first, second) -> Bool in
return first.pk < second.pk
}
cell.messagesLists = messages
cell.messageLabel.text = sorted[indexPath.row].text
if sorted[indexPath.row].from_user == userID {
cell.isIncoming = false
}
else if sorted[indexPath.row].from_user != userID {
cell.isIncoming = true
}
return cell
}
}
The cells are being reused every time, and to switch modes from .sent to .received, you have to deactivate previous constraints. Add two arrays of constraints for both states, and deactivate the previous array and activate the new one.
In your case you just append constraints, but don't remove them
var receivedConstraints = [NSLayoutConstraint]()
var sentConstraints = [NSLayoutConstraint]()
...
final func changeCellMode(to mode: SNKMessage.Mode, didChangeMessageMode: (Bool) -> ()) {
if let _previousMode = previousMessageMode, _previousMode == mode {
didChangeMessageMode(false)
messageBackground.setNeedsDisplay()
return
}
didChangeMessageMode(true)
if mode == .outgoing {
NSLayoutConstraint.deactivate(receivedConstraints)
NSLayoutConstraint.activate(sentConstraints)
} else {
NSLayoutConstraint.deactivate(sentConstraints)
NSLayoutConstraint.activate(receivedConstraints)
}
messageBackground.messageMode = mode
previousMessageMode = mode
setNeedsLayout()
}
First of all, i recommend you to use collectionview for this kind of a view. In this part of source, you should not set constraints every time. By the way please watch the link below. :)
https://youtu.be/kR9cf_K_9Tk

fetch data from firebase and use textfield for preview and update purposes

I want to use the same objects of one ViewController for saving into Firebase and for fetching saved data to preview and update if necessary.
Initially I used textfield in static cells it worked pretty well, but fail to insert text in textfield in dynamic cell.
When I call print function for the textfield in console it prints out correct value, but doesn't show anything on screen of simulator. I even tried to use simple strait text string to put it into textfield, but unsuccessful.
here is related code from TextMessageViewController, which i use for sending data to Firebase through textfields in dynamical tablecells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TextInputTableViewCell = receiverEmailTableView.dequeueReusableCell(withIdentifier: "ReceiverEmail") as! TextInputTableViewCell!
cell.recepientEmailTF.delegate = self
cell.recepientEmailTF.tag = indexPath.row
return cell
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
if MyGlobalVariables.emails.count <= 3 {
print("tag master = \(textField.tag)")
switch textField.tag {
case 0:
if MyGlobalVariables.emails.endIndex == 0 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[0] = textField.text!
case 1:
if MyGlobalVariables.emails.endIndex == 1 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[1] = textField.text!
case 2:
if MyGlobalVariables.emails.endIndex == 2 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[2] = textField.text!
default:
print("exceeded")
}
DispatchQueue.main.async {
self.receiverEmailTableView.reloadData()
}
} else {
print("exceeded emails limit, add alert")
}
}
Portion of code from TextPreviewViewController from where I want to get firebase data and add it to texfields. This viewcontroller is connected to preview viewcontroller in storyboard
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let edit = UITableViewRowAction(style: .default, title: "Edit") { (action, indexPath) in
let newMessageVC = self.storyboard?.instantiateViewController(withIdentifier: "TextMessage") as? TextMessageViewController
newMessageVC?.modalPresentationStyle = .overCurrentContext
self.present(newMessageVC!, animated: true, completion: {
let updateButton = newMessageVC?.saveOrUpdateButton
updateButton?.titleLabel?.text = "Update"
let messageBody = newMessageVC?.messageTV
let dateField = newMessageVC?.tergetDateTF
let action = MyGlobalVariables.refMessages.child(MyGlobalVariables.uidUser!)
// CONCERN POINT: from here->
let cell1: TextInputTableViewCell = newMessageVC?.receiverEmailTableView.dequeueReusableCell(withIdentifier: "ReceiverEmail") as! TextInputTableViewCell!
cell1.recepientEmailTF.delegate = self
cell1.recepientEmailTF.allowsEditingTextAttributes = true
let texfielf = cell1.recepientEmailTF
MyGlobalVariables.emails.removeAll()
MyGlobalVariables.emails = ["","",""]
// cell1.recepientEmailTF.text = "Suka blyat" <- even this simple text doesnt appear
MyGlobalVariables.emails[0].append(self.messages[indexPath.row].email1!)
texfielf?.text = MyGlobalVariables.emails[0]
//cell1.recepientEmailTF.text = MyGlobalVariables.emails[0] <- this code also doesnt work
MyGlobalVariables.emails[1].append(self.messages[indexPath.row].email2!)
texfielf?.text = self.messages[indexPath.row].email2!
MyGlobalVariables.emails[2].append(self.messages[indexPath.row].email3!)
texfielf?.text = self.messages[indexPath.row].email3!
DispatchQueue.main.async {
newMessageVC?.receiverEmailTableView.reloadData()
}
//CONCERN POINT: ->up to here
messageBody?.text = self.messages[indexPath.row].message!
dateField?.text = self.messages[indexPath.row].setupDate!
if let autoID2 = self.messages[indexPath.row].autoID {
MyGlobalVariables.messageForUpdate1.append(autoID2) }
})
}
return [edit]
}
My UITableViewCell class
public class TextInputTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var recepientEmailTF: UITextField!
override public func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override public func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}}
I would appreciate any help or advices.

How to print value in UILabel from the values of TableView dynamically

I'm having a tableView with a custom cell, whenever I click the checkbox button the value inside the cell increases i.e.,(0 to 1) in cell, and on uncheck value decreases, that works perfectly. But whenever I try to print those values from the cell to a UILabel outside tableView, the values are not changing.
This is the below code I have Used
var data = [[String: AnyObject]]()
func getDetails() {
let paymentURL = paymentListURL + String(28) + "&student_id=" + String(33)
Alamofire.request(paymentURL).responseJSON { (response) in
if ((response.result.value) != nil) {
var jsonVar = JSON(response.result.value!)
print(jsonVar)
if let da = jsonVar["types"].arrayObject {
self.data = da as! [[String:AnyObject]]
}
if self.data.count > 0 {
self.tableView.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TabCell
cell.checkB.tag = indexPath.row
let ip = data[indexPath.row]
cell.nameText.text = ip["title"] as? String
if cell.nameText.text == "Mandatory testing" {
cell.checkB.checkState = .checked
cell.backgroundColor = UIColor.lightGray
cell.checkB.backgroundColor = UIColor.lightGray
}
if ip["mandatory"] as? String == "yes" {
moneyText.text = ip["amount"] as? String
//moneyText is UILabel outside Tableview
cell.amountValue.text = ip["amount"] as? String
cell.checkB.isEnabled = false
} else {
moneyText.text = "0"
if cell.amountValue.text == "1"{
print("ONE")
}
}
return cell
}
func didPressButton(_ tag: Int) {
let indexPath = IndexPath.init(row: 0, section: 0)
let cell = tableView.cellForRow(at: indexPath) as! TabCell
moneyText.text = String(cell.someValue)
}
And for TableviewCell I Used
protocol TabCellDelegate {
func didPressButton(_ tag: Int)
}
class TabCell: UITableViewCell {
#IBOutlet weak var checkB: M13Checkbox!
#IBOutlet weak var nameText: UILabel!
#IBOutlet weak var amountValue: UILabel!
var someValue: Int = 0 {
didSet {
amountValue.text = "\(someValue)"
}
}
#IBAction func checkBAction(_ sender: M13Checkbox) {
cellDelegate?.didPressButton(sender.tag)
if checkB.checkState == .checked {
someValue += 1
} else if checkB.checkState == .unchecked {
someValue -= 1
}
}
}
I tried first adding those values from cell to an Array, and then adding all the values in array and printing in UILabel, but the values are not changing, it was only incrementing.i.e., even after unchecking the checkbox the value is increasing.
I tried even using protocol it did not work for me
Any Help will be appreciated.
You are updating someValue from the checkBAction handler inside the TabCell. The property didSet handler will then update the amountValue label. This is the reason, why the cell's label is being updated.
You do not have any code that updates the moneyText after someValue changed. You only set moneyText.text from tableView(_:cellForRow:), but this is called when a cell is being displayed, maybe multiple times after scrolling etc.
You could do the following:
Create a delegate property inside the cell (use a custom protocol as type)
Set the controller to be that delegate
When the value changes, call a function of that delegate (e.g. call the controller)
Inside that, update the moneyText
As an idea (might not compile because I don't have all your classes):
protocol MyTabCellProtocol {
func checkboxChanged(_ checkbox:M13Checkbox, atRow:Integer)
}
class TabCell: UITableViewCell {
weak delegate:MyTabCellProtocol?
// ...
#IBAction
func checkBAction(_ sender: M13Checkbox) {
if checkB.checkState == .checked {
someValue += 1
} else if checkB.checkState == .unchecked {
someValue -= 1
}
delegate?.checkboxChanged(self, checkB.tag)
}
}
class MyController : UIViewController, MyTabCellProtocol {
func checkboxChanged(_ checkbox:M13Checkbox, atRow:Integer) {
moneyText.text = "\(checkbox.someValue)"
}
}
But if I think further, I would suggest to refactor the whole code a little. The problem I see is that your action handler inside the cell does update the someValue property of the cell, but does not update the outside model (ip["amount"]). I think what you should do is:
Inside the cell's checkBAction, just call the delegate and provide the information about the row that has been modified (self.checkB.tag) and the check state. Do not update the amountValue here!
In the delegate implementation, update the model ip["amount"]
Call reloadRows(at:with:) of the table view to refresh the cell
Then, cellForRow is automatically being called, in which you then update the cell and the outer label.

Conditionally activate UISearchController for iOS8+

I have an app that I would like to target to iOS 7, but am currently unable to do so because it contains a UISearchController which is only available for iOS 8 and up.
I've been trying to modify the search bar with a UISearchDisplayController so that it works in iOS 7, but I just can't get it to work and am getting a little frustrated. So as a temporary measure (while I get better at coding), I would like to disable the search bar for any iOS below 8.0 - which won't impact the end user too much because its only one screen in a much larger app.
The problem is that I haven't been able to figure out how to do this conditionally (e.g., with "if #available(iOS 8.0, *)" ) because the variables "searchController" and "controller" are defined outside of a method or function and so can't be assigned conditionally. I guess conditional statements can only be used within functions and methods? (still learning, as you can see).
So can anyone offer a way for me to conditionally disable the search bar here so I can target iOS 7? My code for this class is below. Thanks!
class RegData2: UITableViewController, UISearchResultsUpdating {
let model = Model()
var prevArray = [String]()
var selectionPrev = String()
var filteredTableData = [String]()
var searchController = UISearchController()
let controller = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
self.searchController = ({
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
self.tableView.tableHeaderView = controller.searchBar
self.definesPresentationContext = true
return controller
})()
// Reload the table
self.tableView.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.searchController.active) && (controller.searchBar.text != "") {
return self.filteredTableData.count
}
else {
return prevArray.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell!
cell.textLabel?.font = UIFont.boldSystemFontOfSize(18)
if (self.searchController.active) && (controller.searchBar.text != "") {
cell.textLabel?.text = filteredTableData[indexPath.row]
return cell
}
else {
cell.textLabel?.text = prevArray[indexPath.row]
return cell
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
controller.searchBar.resignFirstResponder()
performSegueWithIdentifier("regData2ToRegView", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "regData2ToRegView" {
let regView = segue.destinationViewController as! RegView
let indexPath : NSIndexPath = self.tableView.indexPathForSelectedRow!
var selection : String = prevArray[indexPath.row]
if (self.searchController.active) && (self.controller.searchBar.text != "") {
selection = self.filteredTableData[indexPath.row]
}
else {
selection = self.prevArray[indexPath.row]
}
regView.prevSelection = selection
regView.prevSelectionType = selectionPrev
}
}
func updateSearchResultsForSearchController(searchController: UISearchController)
{
if searchController.searchBar.text != ""{
filteredTableData.removeAll(keepCapacity: true)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
if self.selectionPrev != "ed" {
let array = (self.prevArray as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
// edAlert = 0
} else {
let array = (self.prevArray as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
// edAlert = 1
}
self.tableView.reloadData()
} else {
self.tableView.reloadData()
}
}
}
To check version you can do this:
switch UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch) {
case .OrderedSame, .OrderedDescending:
println("iOS >= 8.0")
case .OrderedAscending:
println("iOS < 8.0")
}
But most likely you just need to check if the class is available and then instantiate it:
if NSClassFromString("UISearchController") != nil {
// init and use ...
}
This is called "weakly linked" class.
EDIT:
Also you can use preprocessor to include/exclude any code before compilation, i.e.:
#if __IPHONE_8_0
class RegData2: UITableViewController, UISearchResultsUpdating {
#else
class RegData2: UITableViewController {
#endif
More info here and here and also here.

How to implement UISearchController in iOS8?

I have tried to implement the UISearchController in IOS8 but failed.
The problem is when I have changed the text and the scope button, noting is presented to me.
And it seems that the updateSearchResultsForSearchController function is not even called when I update the search Bar or the scope button.
Here is my code:
class SearchTestController: UITableViewController, UISearchResultsUpdating {
struct Candy {
let category : String
let name : String
}
var searchcontroller = UISearchController(searchResultsController: nil)
func updateSearchResultsForSearchController(searchController: UISearchController) {
filteredcandy = candies.filter() { (candy:Candy) -> Bool in
let scopetest = ( self.category[self.searchcontroller.searchBar.selectedScopeButtonIndex] == "All" ) || ( candy.category == self.category[self.searchcontroller.searchBar.selectedScopeButtonIndex] )
//let texttest = candy.name.rangeOfString(self.searchcontroller.searchBar.text)
//let result = scopetest && (texttest != nil)
return scopetest
}
println(filteredcandy.count)
self.tableView.reloadData()
}
var candies = [Candy]()
var filteredcandy = [Candy]()
var category = ["Chocolate","Hard","Other","All"]
override func viewDidLoad() {
super.viewDidLoad()
// Sample Data for candyArray
self.candies = [Candy(category:"Chocolate", name:"chocolate Bar"),
Candy(category:"Chocolate", name:"chocolate Chip"),
Candy(category:"Chocolate", name:"dark chocolate"),
Candy(category:"Hard", name:"lollipop"),
Candy(category:"Hard", name:"candy cane"),
Candy(category:"Hard", name:"jaw breaker"),
Candy(category:"Other", name:"caramel"),
Candy(category:"Other", name:"sour chew"),
Candy(category:"Other", name:"gummi bear")]
// Reload the table
self.tableView.reloadData()
self.tableView.tableHeaderView = searchcontroller.searchBar
searchcontroller.searchBar.sizeToFit()
searchcontroller.searchBar.showsSearchResultsButton = true
self.definesPresentationContext = true
searchcontroller.searchBar.scopeButtonTitles = category
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchcontroller.active {
return self.candies.count
} else {
return self.candies.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//ask for a reusable cell from the tableview, the tableview will create a new one if it doesn't have any
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
var candy : Candy
// Check to see whether the normal table or search results table is being displayed and set the Candy object from the appropriate array
if searchcontroller.active {
candy = filteredcandy[indexPath.row]
} else {
candy = candies[indexPath.row]
}
// Configure the cell
cell.textLabel!.text = candy.name
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
Add the following lines to viewDidLoad()
searchcontroller.searchResultsUpdater = self
searchcontroller.delegate = self
Update:
Add the following line in viewDidLoad()
searchcontroller.searchBar.delegate = self
Then update the search results in searchBar(_:selectedScopeButtonIndexDidChange:)