Searchbar with Async webservice call not reflect tableview reloadData() - ios

I have tried to load search result on async call so search text won't take much time to enter.
it works on viewDidLoad but when i called up same method on searchbar text enter then it will go through reload data but not reflected on UI.It reflected when i click on cancel button of searchbar. I need to reflect reloadData on each search text entered on searchBar.
I have tried below code: Any help will be most appreciated.
import Foundation
import UIKit
class NSOperations {
lazy var downloadQueue:NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Image Download queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
lazy var filtrationQueue:NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Search Filtration queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
}
class SearchResultController: UIViewController, UITableViewDataSource, UITableViewDelegate,UISearchDisplayDelegate, UISearchBarDelegate
{
#IBOutlet var searchBar: UISearchBar!
#IBOutlet weak var contactsTableView: UITableView!
var genericArr = [Generic]()
var utility = Utility()
var constants = Constants()
var netUtil = NetworkUtil()
var controllerUtil = ControllerUtil()
var parser = Parsers()
var searchString = ""
var filteredTableData = [Generic]()
var searchActive : Bool = false
let pendingOperations:NSOperations = NSOperations()
override func viewDidLoad()
{
super.viewDidLoad()
self.contactsTableView.delegate = self
self.contactsTableView.dataSource = self
self.searchBar.delegate = self
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchActive = true;
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchActive = false
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
filteredTableData.removeAll(keepCapacity: false)
self.filteredTableData = [Generic]()
if searchText != ""
{
searchActive = true
self.suspendAllOperations()
self.search(searchText)
}
else
{
searchActive = false
}
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchActive = false
self.searchBar.resignFirstResponder()
}
func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int {
var count:Int = 0
if self.searchActive == true {
count = self.filteredTableData.count
}
else{
count = self.genericArr.count
}
return count
}
func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell {
let resultCell = self.contactsTableView.dequeueReusableCellWithIdentifier("ResultCell") as! ResultCell
var result:Generic = Generic()
if searchActive == true && self.filteredTableData.count > 0
{
result = self.filteredTableData[indexPath.row]
resultCell.setResultCell(result)
}
else
{
result = self.genericArr[indexPath.row]
resultCell.setResultCell(result)
}
return resultCell
}
func suspendAllOperations () {
pendingOperations.downloadQueue.suspended = true
pendingOperations.filtrationQueue.suspended = true
}
func resumeAllOperations () {
pendingOperations.downloadQueue.suspended = false
pendingOperations.filtrationQueue.suspended = false
}
func search(searchTxt: String){
let searchUrl: String = "\(constants.SERVER_URL)\(constants.SEARCH_RESULT_URL)\(searchTxt.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!)"
pendingOperations.filtrationQueue.addOperationWithBlock({
self.netUtil.callJSONData(searchUrl) {(dataDictionary) -> Void in
self.errorStr = dataDictionary[self.constants.defaultsKeys.RESPONSE_ERROR] as! String
let data: AnyObject? = dataDictionary[self.constants.defaultsKeys.RESPONSE_RESULT]
if(self.errorStr.isEmpty || self.errorStr==""){
if data != nil {
if let jsonNSData = data as? NSData
{
if let resultDict :NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(jsonNSData, options: NSJSONReadingOptions.MutableContainers)) as? NSDictionary{
self.loadData(resultDict)
print("count >> \(self.genericArr.count)")
dispatch_async(dispatch_get_main_queue()) {
self.contactsTableView.reloadData()
}
}
}
}
else{
// self.showError("something is wrong happened")
}
}
else{
// self.showError(self.errorStr)
}
}
})
}
func loadData(resultDict : NSDictionary){
let genArray:[Generic] = parser.getGenericArr(resultDict)
if searchActive == true{
self.filteredTableData = [Generic]()
self.filteredTableData.appendContentsOf(genArray)
}
else{
self.genericArr = [Generic]()
self.genericArr.appendContentsOf(genArray)
}
}
func callJSONData(urlStr: String, callback: ((data: Dictionary<String,AnyObject>) -> Void)!)
{
let url = NSURL(string: urlStr)!
var dict = Dictionary<String,AnyObject>()
var errorStr = ""
if let data = NSData(contentsOfURL: url) {
dict = Dictionary<String,AnyObject>()
self.parser.getJSONResultDataDictionary(data) {(dataDictionary) -> Void in
errorStr = dataDictionary[self.constants.defaultsKeys.RESPONSE_ERROR] as! String
if(errorStr.isEmpty || errorStr==""){
if let dataDict = dataDictionary[self.constants.defaultsKeys.RESPONSE_RESULT] as? Dictionary<String,AnyObject>
{
dict = dataDict
dict[self.constants.defaultsKeys.RESPONSE_ERROR] = errorStr
}
else{
dict[self.constants.defaultsKeys.RESPONSE_ERROR] = errorStr
}
}
else
{
dict[self.constants.defaultsKeys.RESPONSE_ERROR] = errorStr
}
}
}
else{
dict = Dictionary<String,AnyObject>()
dict[self.constants.defaultsKeys.RESPONSE_ERROR] = errorStr
}
callback(data: dict)
}
}

Related

Image not behaving accurately in data search results on TableView

I have data coming from Firebase and when the data is loaded I either want the an image to be hidden or shown based on some logic in my custom cell. It works perfectly fine when the data isn't being filtered but the second I type in the search bar or change the scope bar to a different index the image doesn't behave right.
For example: Index 0 should not have the image and index 1 should. Which is how it displays when it first loads. However, when I search I know the previous index 1 (now index 0) should still have it's image but it doesn't. BUT if I click to go to the detail controller it brings me to the right page. It's like it loads all the accurate info but does the logic on the original index 0. I would love some help as I have been searching for an answer FOREVER. Thank you in advance!
tableViewCell:
class SearchTalentCell: UITableViewCell {
#IBOutlet weak var userProfileImage: UIImageView!
#IBOutlet weak var talentUserName: UILabel!
#IBOutlet weak var selectedImg: UIImageView!
#IBOutlet weak var inviteSentImg: UIImageView!
var prospectRef: FIRDatabaseReference!
//#IBOutlet weak var radioButton: UIButton!
var currentTalent: UserType!
//var delegate: SearchCellDelegate?
func setTalent(talent: UserType) {
currentTalent = talent
currentTalent.userKey = talent.userKey
}
override func awakeFromNib() {
super.awakeFromNib()
let tap = UITapGestureRecognizer(target: self, action: #selector(selectTapped))
tap.numberOfTapsRequired = 1
selectedImg.addGestureRecognizer(tap)
selectedImg.isUserInteractionEnabled = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
/*#IBAction func radioButtonTapped(_ sender: Any) {
delegate?.didTapRadioButton(userKey: currntTalent.userKey, searchSelected: currntTalent.searchSelected!.rawValue, radioButton: radioButton)
}*/
func configureCell(user: UserType, img: UIImage? = nil) {
prospectRef = Cast.REF_PRE_PRODUCTION_CASTING_POSITION.child(ProjectDetailVC.currentProject).child(FIRDataCast.prospect.rawValue).child(CastingDetailVC.positionName).child(user.userKey)
//setTalent(talent: user)
self.talentUserName.text = "\(user.firstName) \(user.lastName)"
//self.inviteSentImg.image = UIImage(named: "inviteSent")
//user.adjustSearchSelected(talent: user, radioButton: radioButton)
prospectRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.inviteSentImg.isHidden = true
print("**Image hidden")
} else {
self.inviteSentImg.image = UIImage(named: "inviteSent")
print("**Image shown")
}
})
//Image Caching
if img != nil {
self.userProfileImage.image = img
} else {
if let imageURL = user.profileImage {
let ref = FIRStorage.storage().reference(forURL: imageURL)
ref.data(withMaxSize: 2 * 1024 * 1024, completion: { (data, error) in
if error != nil {
print("ZACK: Unable to download image from Firebase Storage")
} else {
print("ZACK: Image downloaded from Firebase Storage")
if let imgData = data {
if let img = UIImage(data: imgData) {
self.userProfileImage.image = img
SearchTalentVC.userProfileImageCache.setObject(img, forKey: imageURL as NSString)
}
}
}
})
}
}
}
Viewcontroller:
class SearchTalentVC: UITableViewController/*, SearchCellDelegate*/ {
var searchingRole = [Cast]()
var unfilteredTalent = [UserType]()
var filteredTalent = [UserType]()
var selectedTalent = [UserType]()
var matchingTalentUserKeys = [String]()
var isFiltered = false
var prospectRef: FIRDatabaseReference!
static var userProfileImageCache: NSCache<NSString, UIImage> = NSCache()
let searchController = UISearchController(searchResultsController: nil)
//#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search Talent"
searchController.searchBar.barStyle = .black
navigationItem.searchController = searchController
definesPresentationContext = true
searchController.searchBar.scopeButtonTitles = ["All", "Role Specific"]
searchController.searchBar.tintColor = UIColor.white
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
getTalentProfiles()
}
func searchBarIsEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredTalent = unfilteredTalent.filter({ (talent : UserType) -> Bool in
let doesTalentMatch = (scope == "All") || doesUserKeyMatch(talent: talent.userKey)
if searchBarIsEmpty() {
return doesTalentMatch
} else {
let fullName = "\(talent.firstName) \(talent.lastName)"
return doesTalentMatch && fullName.lowercased().contains(searchText.lowercased())
}
})
tableView.reloadData()
}
func doesUserKeyMatch(talent: String) -> Bool {
self.filterRoleFeature()
return matchingTalentUserKeys.contains(talent)
}
func isSearching() -> Bool {
let searchBarScopeIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
return searchController.isActive && (!searchBarIsEmpty() || searchBarScopeIsFiltering)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if isSearching() {
return filteredTalent.count
} else {
return unfilteredTalent.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "userSearchCell"
if let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? SearchTalentCell {
var talent: UserType
if isSearching() {
print("we are searching")
talent = self.filteredTalent[indexPath.row]
print("indexPath: \(indexPath.row)")
} else {
print("we are not searching")
talent = self.unfilteredTalent[indexPath.row]
}
if let imageURL = talent.profileImage {
if let img = SearchTalentVC.userProfileImageCache.object(forKey: imageURL as NSString) {
cell.configureCell(user: talent, img: img)
} else {
cell.configureCell(user: talent)
//cell.delegate = self
}
return cell
} else {
cell.configureCell(user: talent)
//cell.delegate = self
return SearchTalentCell()
}
} else {
return SearchTalentCell()
}
}
extension SearchTalentVC: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
self.tableView.reloadData()
}
}
extension SearchTalentVC: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
If you are hidding image in If part then you should put logic of showing image also in else block. See if this solve your problem.
if let _ = snapshot.value as? NSNull {
self.inviteSentImg.isHidden = true
print("**Image hidden")
} else {
self.inviteSentImg.isHidden = false
self.inviteSentImg.image = UIImage(named: "inviteSent")
print("**Image shown")
}

Accessing struct object array in no of rows in section returning null

I am trying to download data and put it in struct objects and trying to load data in table view .I am downloading it in to array and append it to struct object.when I am taking return array.count in no of rows in section its working when I use return objectArray[section].funcName.count its not working values are getting late to download also
import UIKit
import Alamofire
class GalleryVC: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var galleryTable: UITableView!
var imageUrlArray:[String] = [String]()
var imageCount:[String] = [String]()
var funName1:[String] = [String]()
var gaimage1:String = ""
var gacount1:String = ""
var funname1:String = ""
struct Objects {
var imageName : [String]!
var imageCount : [String]!
var funcName:[String]!
}
var objectArray = [Objects]()
var objectArrayFilter = [Objects]()
var inSearchMode = false
override func viewDidLoad() {
super.viewDidLoad()
downloadGalleryList()
galleryTable.delegate = self
galleryTable.dataSource = self
searchBar.delegate = self
self.hideKeyboardWhenTappedAround()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
print(objectArray[section].funcName.count)
return objectArray[section].funcName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier:"gallerycell", for: indexPath) as? GalleryListCell{
if inSearchMode{
cell.galleryImage.sd_setImage(with: URL(string: objectArrayFilter[indexPath.section].imageName[indexPath.row]), placeholderImage: UIImage(named: "1862205"))
cell.galleryphotono.text = objectArrayFilter[indexPath.section].imageCount[indexPath.row]+" photos"
cell.galleryFunction.text = objectArrayFilter[indexPath.section].funcName[indexPath.row]
return cell
}
cell.galleryImage.sd_setImage(with: URL(string: objectArray[indexPath.section].imageName[indexPath.row]), placeholderImage: UIImage(named: "1862205"))
cell.galleryphotono.text = objectArray[indexPath.section].imageCount[indexPath.row]+" photos"
cell.galleryFunction.text = objectArray[indexPath.section].funcName[indexPath.row]
return cell
}
else{
return UITableViewCell()
}
}
func downloadGalleryList(){
let bmiChapterUrl = URL(string:Gallery_List)!
Alamofire.request(bmiChapterUrl).responseJSON{ response in
let result = response.result
print(response)
print(result)
if let dict = result.value as? Dictionary<String,AnyObject>{
if let bmi = dict["result"] as? [Dictionary<String,AnyObject>]
{
for obj in bmi {
if let gaimage = obj["image"] as? String
{
print(gaimage)
self.gaimage1 = gaimage
self.imageUrlArray.append(gaimage)
}
if let gacount = obj["count"] as? String
{
self.gacount1 = gacount
print(gacount)
self.imageCount.append(gacount)
}
if let funname = obj["event"] as? String
{
print(funname)
self.funname1 = funname
self.funName1.append(funname)
}
}
}
}
print(self.imageUrlArray,self.imageCount,self.funName1
)
self.objectArray.append(Objects(imageName: self.imageUrlArray, imageCount:self.imageCount,funcName: self.funName1))
print(self.objectArray)
self.galleryTable.reloadData()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
inSearchMode = false
view.endEditing(true)
galleryTable.reloadData()
} else {
inSearchMode = true
objectArrayFilter = objectArray.filter { $0.imageName.contains(where: { $0.contains(searchBar.text!) }) }
print(objectArrayFilter)
galleryTable.reloadData()
}
}
}

Type 'BusinessData' has no member 'sortUsingComparator'

i am getting some data from one url and i am try to display in table view. before that i directly used all array , search, sorting.Its worked well.But now, when i create separate class for my table view i am getting this error
Type 'BusinessData' has no member 'sortUsingComparator' in my sorting function.Here i gave 3 button action.Inside that button action i declaring this sorting code.But now i am getting this error.
my bussinessData.swift class
import UIKit
class BusinessData {
var BusinessName: String?
var Address: String?
var Rating: Float?
var ContactNumber: String?
init(json: NSDictionary) {
self.BusinessName = json["business_name"] as? String
self.Address = json["location"] as? String
self.Rating = json["__v"] as? Float
self.ContactNumber = json["phone_no"] as? String
}
}
My viewcontroller.swift code:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var isTapped:Bool? // cell tap checking bool
var selectedIndex:NSIndexPath?
#IBOutlet weak var RightMenu: UIView!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView! // UITable view declaration
var arrDict = [BusinessData]() // array to store the value from json
var isSearching:Bool?
var arrSearch:NSMutableArray=[]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.jsonParsingFromURL() // call the json method
searchBar.returnKeyType = UIReturnKeyType.Done;
searchBar.hidden = true;
// nib for custom cell (table view)
let nib = UINib(nibName:"customCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
indicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 90, 90))
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
indicator.center = self.view.center
indicator.color = UIColor .redColor()
self.view.addSubview(indicator)
}
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "searchMethod:", name: "search", object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: "endSearch", name: "endSearch", object: nil);
}
// web services method
func jsonParsingFromURL ()
{
let url:NSURL = NSURL(string: "http://sample url/Fes?current_location=toronto&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyIkX18")!
if let JSONData = NSData(contentsOfURL: url)
{
if let json = (try? NSJSONSerialization.JSONObjectWithData(JSONData, options: [])) as? NSDictionary
{
if let reposArray = json["data"] as? [NSDictionary]
{
for item in reposArray
{
let itemObj = item as? Dictionary<String,AnyObject>
let b_type = itemObj!["business_type"]?.valueForKey("type")
if (b_type as? String == "Taxis")
{
arrDict.append(BusinessData(json: item))
}
}
}
}
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
if(isSearching == true)
{
return arrSearch.count;
}
return self.arrDict.count
}
// number of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
// height for each cell
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return cellSpacingHeight
}
// calling each cell based on tap and users ( premium / non premium )
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell:customCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! customCell
if(isSearching == true)
{
cell.vendorName.text = arrDict[indexPath.section].BusinessName
cell.vendorAddress.text = arrDict[indexPath.section].Address
cell.VendorRating.rating = arrDict[indexPath.section].Rating!
}
else
{
cell.vendorName.text = arrDict[indexPath.section].BusinessName
cell.vendorAddress.text = arrDict[indexPath.section].Address
cell.VendorRating.rating = arrDict[indexPath.section].Rating!
}
return cell
}
// MARK:
// MARK: Sort Method
#IBAction func sortByRevBtnPress(sender: AnyObject)
{
self.indicator.startAnimating()
self.indicator.hidden = false
RightMenu.hidden = true
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(1 * NSEC_PER_SEC)), dispatch_get_main_queue()){
self.indicator.stopAnimating()
self.indicator.hidden = true
};
self.tableView.reloadData()
}
#IBAction func sortByAZBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["business_name"] as? String, name2 = dict2["business_name"] as? String
{
return name1.compare(name2)
}
return .OrderedAscending
}
self.tableView.reloadData()
}
#IBAction func sortByRatingBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["rating"] as? String, name2 = dict2["rating"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
#IBAction func sortByRecentBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["created_at"] as? String, name2 = dict2["created_at"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
// MARK:
// MARK: Search Method
func endSearch()
{
if(isSearching == false)
{
isSearching = true;
searchBar.hidden = false;
yConstraint.constant = 47;
self.view.layoutIfNeeded();
}
else
{
isSearching = false;
searchBar.hidden = true;
tableView.reloadData();
yConstraint.constant = 3;
self.view.layoutIfNeeded();
self.view.endEditing(true);
}
}
func searchMethod(notification:NSNotification)
{
if(isSearching == true)
{
isSearching = false;
searchBar.hidden = true;
tableView.reloadData();
yConstraint.constant = 3;
self.view.layoutIfNeeded();
self.view.endEditing(true);
}
else
{
isSearching = true;
searchBar.hidden = false;
yConstraint.constant = 47;
self.view.layoutIfNeeded();
}
}
// MARK:
// MARK: SearchBar Method
func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
{
arrSearch = [];
for(var i=0;i<arrDict.count;i++)
{
if((BusinessData.objectAtIndex(i).objectForKey("name")?.lowercaseString?.containsString(searchText.lowercaseString)) == true)
{
arrSearch.addObject(BusinessData.objectAtIndex(i));
}
}
tableView.reloadData();
}
func searchBarSearchButtonClicked(searchBar: UISearchBar)
{
self.view.endEditing(true);
isSearching = false;
searchBar.hidden = true;
tableView.reloadData();
yConstraint.constant = 3;
self.view.layoutIfNeeded();
}
}
I am getting error in this these button action method:
#IBAction func sortByAZBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["business_name"] as? String, name2 = dict2["business_name"] as? String
{
return name1.compare(name2)
}
return .OrderedAscending
}
self.tableView.reloadData()
}
#IBAction func sortByRatingBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["rating"] as? String, name2 = dict2["rating"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
#IBAction func sortByRecentBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["created_at"] as? String, name2 = dict2["created_at"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
In every method i am getting this error Type 'BusinessData' has no member 'sortUsingComparator'..In this below line :
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
Please help me out
Thanks
BusinessData is a model class. It looks like what you really want to do is to sort var arrDict = [BusinessData]() - an array of BusinessData instances.
Your current code BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in is trying to call a class method sortUsingComparator on BusinessData model class and expects to get 2 dictionaries back.
What you want is something more like:
arrDict.sortUsingComparator { (b1, b2) -> NSComparisonResult in
where b1 and b2 are instances of BusinessData, not dictionaries.

Send array by segue to new view controller swift iOS 9

I am attempting to send an array of data to a new view controller and I'm currently getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
Im using the API data from www.thecocktaildb.com
Example:
http://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita
Not sure what I'm doing wrong. Tried debugging and checking values before the segue in my search view controller and they're accurate.
Heres my code:
Main Storyboard
SearchViewController
class SearchViewController: UIViewController, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TableView: UITableView!
#IBOutlet weak var SearchBar: UISearchBar!
var valueToPass:Drinks!
var isSearching : Bool = false
class Drinks {
var idDrink: Int = 0
var strDrink: String = ""
var strCategory: String = ""
var strAlcoholic: String = ""
var strGlass: String = ""
var strInstructions: String = ""
var strDrinkThumb: String = ""
var strIngredient1: String = ""
var strIngredient2: String = ""
var strIngredient3: String = ""
var strIngredient4: String = ""
var strIngredient5: String = ""
var strIngredient6: String = ""
var strIngredient7: String = ""
var strIngredient8: String = ""
var strIngredient9: String = ""
var strIngredient10: String = ""
var strIngredient11: String = ""
var strIngredient12: String = ""
var strIngredient13: String = ""
var strIngredient14: String = ""
var strIngredient15: String = ""
var strMeasure1: String = ""
var strMeasure2: String = ""
var strMeasure3: String = ""
var strMeasure4: String = ""
var strMeasure5: String = ""
var strMeasure6: String = ""
var strMeasure7: String = ""
var strMeasure8: String = ""
var strMeasure9: String = ""
var strMeasure10: String = ""
var strMeasure11: String = ""
var strMeasure12: String = ""
var strMeasure13: String = ""
var strMeasure14: String = ""
var strMeasure15: String = ""
}
var TableData:Array< Drinks > = Array < Drinks >()
override func viewDidLoad() {
super.viewDidLoad()
for subView in self.SearchBar.subviews
{
for subsubView in subView.subviews
{
if let textField = subsubView as? UITextField
{
textField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""))
}
}
}
self.SearchBar.delegate = self
self.TableView.delegate = self
self.TableView.dataSource = self
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if self.SearchBar.text!.isEmpty {
self.isSearching = false
}else{
self.isSearching = true
let userSearchInput = self.SearchBar.text!.lowercaseString
let newString = userSearchInput.stringByReplacingOccurrencesOfString(" ", withString: "%20", options: NSStringCompareOptions.LiteralSearch, range: nil)
let postEndpoint: String = "http://www.thecocktaildb.com/api/json/v1/1/search.php?s=" + newString
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling GET on www.thecocktaildb.com")
print(error)
return
}
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
}
var count = 1
if let drinks = post["drinks"] as? [NSDictionary] {
self.TableData.removeAll()
for drink in drinks {
let adrink = Drinks()
if let strDrink = drink["strDrink"] as? String {
print(String(count) + ". " + strDrink)
adrink.strDrink = strDrink
count++
}
if let strCategory = drink["strCategory"] as? String {
print(" Category: " + strCategory)
adrink.strCategory = strCategory
}
if let strDrinkThumb = drink["strDrinkThumb"] as? String {
print(" Thumbnail Image: " + strDrinkThumb)
adrink.strDrinkThumb = strDrinkThumb
}
self.TableData.append(adrink)
self.TableView.reloadData()
}
}
})
task.resume()
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
//title = TableData[indexPath.row].strDrink
cell.textLabel?.text = TableData[indexPath.row].strDrink;
let imageString = TableData[indexPath.row].strDrinkThumb
if (imageString == ""){
let noDrinkImage : UIImage = UIImage(named: "noimage.jpg")!
cell.imageView!.image = noDrinkImage
}else{
let drinkImage = UIImage(data: NSData(contentsOfURL: NSURL(string:TableData[indexPath.row].strDrinkThumb)!)!)
cell.imageView!.image = drinkImage
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
print(TableData[indexPath.row].strDrink)
valueToPass = TableData[indexPath.row]
//self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
}
// hide kwyboard when search button clicked
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
self.SearchBar.resignFirstResponder()
}
// hide keyboard when cancel button clicked
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.SearchBar.text = ""
self.SearchBar.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
}
}
}
DrinkViewController.swift
class DrinkViewController: UIViewController {
#IBOutlet weak var DrinkNameLabel: UILabel!
var passedValue : SearchViewController.Drinks!
override func viewDidLoad() {
super.viewDidLoad()
DrinkNameLabel.text = passedValue!.strDrink
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Do it like this instead
In your didSelectRowAtIndexPath pass the array
self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
Here you need to pass the array to your DrinkViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
// declare myArray in your drinkViewController and then assign it here
// now your array that you passed will be available through myArray
drinkViewController.myArray = sender
}
}
Update
After I got your project I noticed that the issue you had was that you did drag a segue from the tableView to the drinksController directly - what happened is that didSelectRowAtIndexPath will not be called and your sender will always be nil drinkViewController.myArray = sender as! Drinks.
I changed that by dragging the segue from the viewController to the drinksController instead.

EXC_BAD_ACCESS When I present view controller with market inside

I have a problem presenting a view controller with a Mapkit inside. The first time I presented it works ok, but when I presented again it throw an EXC_BAD_ACCESS ERROR. Programming language is swift. Any help is appreciated.
Xcode 6.4. iOS 8
ViewController.swift
#IBAction func OnClickTallaCamiseta(sender: AnyObject)
{
txtTallaCamiseta.endEditing(true);
//ocultarTallaCamiseta();
self.performSegueWithIdentifier("mostrarMapa", sender: self)
}
func hecho(controller: MapaController, ciudad: String, departamento: String, pais: String)
{
navigationController?.setNavigationBarHidden(true, animated: true);
ciudadSeleccionada = ciudad;
departamentoSeleccionado = departamento;
paisSeleccionado = pais;
var label:String = "";
if(ciudadSeleccionada != "NO_DATA")
{
label += ciudadSeleccionada;
}
if(departamentoSeleccionado != "NO_DATA")
{
label += ", " + departamentoSeleccionado;
}
if(paisSeleccionado != "NO_DATA")
{
label += ", " + paisSeleccionado;
}
lblCiudadEres.text = label;
self.navigationController?.popViewControllerAnimated(true);
}
func terminado(controller: MapaController)
{
println("terminado");
navigationController?.setNavigationBarHidden(true, animated: true);
self.navigationController?.popViewControllerAnimated(true);
}
MapaController.swift
import Foundation
import UIKit
import GoogleMaps
import MapKit
import CoreLocation
protocol MapaControllerDelegate
{
func terminado(controller:MapaController);
func hecho(controller:MapaController, ciudad:String, departamento:String, pais:String);
}
class MapaController : UIViewController, UITableViewDataSource, UITableViewDelegate,
GPSDelegate, MKMapViewDelegate
{
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var btnDone: UIBarButtonItem!
#IBOutlet weak var txtSearch: UITextField!
var locationManager:CLLocationManager = CLLocationManager();
var camera:GMSCameraPosition? = nil;
var aqui:CLLocationCoordinate2D? = nil;
var ne:CLLocationCoordinate2D? = nil;
var sw:CLLocationCoordinate2D? = nil;
var bounds:GMSCoordinateBounds? = nil;
var placesClient:GMSPlacesClient = GMSPlacesClient();
var data:[GMSAutocompletePrediction] = [GMSAutocompletePrediction]();
var ciudad = "";
var departamento = "";
var pais = "";
var delegate:MapaControllerDelegate? = nil;
var gps = GPSLocation;
let filter = GMSAutocompleteFilter();
required init(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
override func viewDidLoad()
{
super.viewDidLoad();
placesClient = GMSPlacesClient();
filter.type = GMSPlacesAutocompleteTypeFilter.Geocode;
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell");
self.tableView.hidden = true;
self.btnDone.enabled = false;
navigationController?.setNavigationBarHidden(false, animated: true);
//setMarkerAndMoveCamera(gps.lat, longitud: gps.long);
gps.gpsDelegate = self;
println("TERMINA"); }
#IBAction func OnTextChanged(sender: AnyObject)
{
if(!txtSearch.text.isEmpty)
{
//println("Searching for '\(self.txtSearch.text)'");
placesClient.autocompleteQuery(self.txtSearch.text,
bounds: bounds,
filter: filter,
callback: { (results, error) -> Void in
if error != nil
{
println("Autocomplete error \(error) for query '\(self.txtSearch.text)'")
return
}
//println("Populating results for query '\(self.txtSearch.text)'");
self.data = [GMSAutocompletePrediction]();
for result in results!
{
if let result = result as? GMSAutocompletePrediction
{
self.data.append(result)
}
}
self.tableView.reloadData();
self.tableView.hidden = false;
if(!self.btnDone.enabled)
{
self.btnDone.enabled = true;
}
});
}
else
{
self.data = [GMSAutocompletePrediction]()
self.tableView.reloadData()
self.tableView.hidden = true;
}
}
func CoordUpdated(latitud: Double, longitud: Double)
{
moverCamara(latitud, longitud: longitud);
aqui = CLLocationCoordinate2DMake(latitud, longitud);
ne = CLLocationCoordinate2DMake(aqui!.latitude + 1, aqui!.longitude + 1);
sw = CLLocationCoordinate2DMake(aqui!.latitude - 1, aqui!.longitude - 1);
bounds = GMSCoordinateBounds(coordinate: ne!, coordinate: sw!);
}
func CoordenadasGuardadas(exito: Bool){}
func VisitaMarcada(exito: Bool){}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.data.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell;
cell.textLabel?.text = self.data[indexPath.row].attributedFullText.string;
return cell;
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
txtSearch.text = self.data[indexPath.row].attributedFullText.string;
txtSearch.endEditing(true);
var placeId:String = self.data[indexPath.row].placeID;
tableView.hidden = true;
placesClient.lookUpPlaceID(placeId,
callback: {(place, error) -> Void in
if error != nil
{
println("lookup place id query error: \(error!.localizedDescription)")
return
}
if place != nil
{
var coordenada:CLLocationCoordinate2D = place!.coordinate;
var lat = coordenada.latitude;
var long = coordenada.longitude;
self.setMarkerAndMoveCamera(lat, longitud: long);
var array = split(self.data[indexPath.row].attributedFullText.string) {$0 == ","};
if(array.count == 3)
{
self.ciudad = array[0];
self.departamento = array[1];
self.pais = array[2];
}
else if(array.count == 2)
{
self.ciudad = array[0];
self.departamento = "NO_DATA";
self.pais = array[1];
}
else
{
self.ciudad = array[0];
self.departamento = "NO_DATA";
self.pais = "NO_DATA";
}
}
else
{
println("No place details for \(placeId)")
}
});
}
func moverCamara(latitud:Double, longitud:Double)
{
/*let location = CLLocationCoordinate2D(latitude: latitud, longitude: longitud)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
mapa.setRegion(region, animated: true)*/
}
func setMarkerAndMoveCamera(latitud:Double, longitud:Double)
{
/*let location = CLLocationCoordinate2D(latitude: latitud, longitude: longitud)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
mapa.setRegion(region, animated: true)
let annotationsToRemove = self.mapa.annotations.filter { $0 !== self.mapa.userLocation }
mapa.removeAnnotations( annotationsToRemove )
let annotation = MKPointAnnotation()
annotation.coordinate = location;
annotation.title = NSLocalizedString("label_ciudad_encontrada",comment:"label_ciudad_encontrada");
mapa.addAnnotation(annotation);*/
}
#IBAction func OnDone(sender: AnyObject)
{
delegate?.hecho(self, ciudad: ciudad, departamento: departamento, pais: pais);
}
#IBAction func OnCancel(sender: AnyObject)
{
delegate?.terminado(self);
}
override func viewWillDisappear(animated:Bool)
{
self.tableView.delegate = nil;
}
#IBAction func onCancelar(sender: AnyObject)
{
delegate?.terminado(self);
}
}
you need to identify the cell, in this case with "cell".
select your tableview, next select prototype cells to 1 in attributes inspector.
Expand the Table View, and select the viewCell
In option the option "identifier" put "cell".

Resources