I have already implement tableview and searchbar, and show skills vName on row and trade VName on section
my issue is,
I want to show only skills vName when search in searchbar in updateSearchResultsForSearchController method
i have tried that method but cannot success.
#JSON Response from API
{
"category": [
{
"iTraderCategoryId": "001",
"vName": "Build",
"vCategoryCode": "builder",
"skill": [
{
"iTraderSkillId": "1",
"iTraderCategoryId": "11",
"vName": "skillName1"
},
{
"iTraderSkillId": "2",
"iTraderCategoryId": "22",
"vName": "skillName2"
}
]
},
{
"iTraderCategoryId": "002",
"vName": "TV",
"vCategoryCode": "tv",
"skill": [
{
"iTraderSkillId": "3",
"iTraderCategoryId": "33",
"vName": "skillName3"
},
{
"iTraderSkillId": "4",
"iTraderCategoryId": "44",
"vName": "skillName4"
},
{
"iTraderSkillId": "5",
"iTraderCategoryId": "55",
"vName": "skillName5"
}
]
}
]
}
#my tableview controller code is,
import UIKit
import RealmSwift
import Alamofire
import RxSwift
//class SectionTableViewController: UITableViewController, UISearchResultsUpdating,UISearchBarDelegate, UISearchControllerDelegate {
class SectionTableViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {
var selectedIngredients : Set<IndexPath> = []
var searchController : UISearchController!
var searchTradeSkills : UISearchController!
var selectedTrad: Trade?
var filteredObjects = [SkillDTO]()
var isSearching = false
var lastSelectedIndexPath : Int?
var totalSkills = [Int : Bool]()
// var filterData : [String]!
private let viewModel = TradeSelectionViewModel()
var selectedTradeHandler: ((_ trade: Trade) -> Void)?
private let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
searchBarSetup()
callAPI()
}
func searchBarSetup() {
tableView.allowsMultipleSelection = true
tableView.estimatedRowHeight = tableView.rowHeight
tableView.rowHeight = UITableView.automaticDimension
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
}
func callAPI(){
UserApi().getTradieSkills().subscribe(onNext: { (result: Result<TradeSelectionViewModel>) in
switch result {
case .success(model: _):
print(result)
case .error(error: _):
print("error")
}
}).disposed(by: bag)
}
// i don't know how to implement and show only skills when search
func updateSearchResults(for searchController: UISearchController) {
let searchString = searchController.searchBar.text!
print(viewModel.categorySkills)
if searchString.isEmpty {
filteredObjects.removeAll()
}else{
let filterObject = viewModel.categorySkills.map({
$0.skill
})
.reduce([], +).filter({
($0.vName?.lowercased().contains(searchString.lowercased()))!
})
filteredObjects = filterObject
// print("filter data is \(filteredObjects)")
// let filterObject = viewModel.categorySkills.map({
// $0.skill
// })
// .reduce([], +).filter({
// ($0.vName?.lowercased().contains(searchString.lowercased()))!
// })
// let filterObjects = viewModel.catSkills.compactMap({
// $0.vName?.filter({
// $0.lowercased().contains(searchString.lowercased())
// })
// })
// filteredObjects = filterObject
// print("filter data count is in search before \(filteredObjects.count)")
// print("filter data is \(filteredObjects)")
}
if searchController.isActive {
isSearching = true
}else{
isSearching = false
}
tableView.reloadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.categorySkills.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching && searchController.searchBar.text != ""{
return filteredObjects.count
//return filteredObjects[section].skillName.count
// return filteredObjects[section].count //final
}else{
let section = viewModel.categorySkills[section]
return section.skill.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if isSearching && searchController.searchBar.text != "" {
let text =
filteredObjects[indexPath.row].vName
cell.textLabel?.text = text
}else{
cell.textLabel?.text = viewModel.categorySkills[indexPath.section].skill[indexPath.row].vName
}
if selectedIngredients.contains(indexPath){
cell.accessoryType = .checkmark
cell.backgroundColor = UIColor.lightGray
}else{
cell.accessoryType = .none
cell.backgroundColor = .none
}
return cell
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let titleText = viewModel.categorySkills[section].vName
return titleText
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
lastSelectedIndexPath = indexPath.section
if self.selectedIngredients.contains(indexPath){
self.selectedIngredients.remove(indexPath)
totalSkills[indexPath.row] = false
}else{
self.selectedIngredients.insert(indexPath)
totalSkills[indexPath.row] = true
}
self.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
print(selectedIngredients)
if lastSelectedIndexPath != nil {
if lastSelectedIndexPath != indexPath.section {
selectedIngredients.removeAll()
print(selectedIngredients)
}
}
return indexPath
}
}
Trade Structure
import Foundation
struct Trade {
let categoryId: String
let trade: String
let skill : [Skills]
}
struct Skills {
let skillId: String
let skillName: String
}
#ViewModelFile
import Foundation
import RealmSwift
class TradeSelectionViewModel {
init() {
load()
}
private(set) var trades: [Trade] = []
var categorySkills : Results<TradeCategorySkillDTO> = DataManager.shared.get()
private func load() {
trades.removeAll()
categorySkills = categorySkills.sorted(byKeyPath: "vName")
categorySkills.forEach({
trades.append(Trade(categoryId: $0.iTraderCategoryID, trade: $0.vName))
})
// print(trades)
}
}
RealmFile for Trade data
import Foundation
import Realm
import RealmSwift
#objcMembers class TradeCategorySkillDTO: Object, Codable {
dynamic var iTraderCategoryID: String = ""
dynamic var vName: String = ""
dynamic var skill = List<SkillDTO>()
enum CodingKeys: String, CodingKey {
case iTraderCategoryID = "iTraderCategoryId"
case vName
case skill
}
override static func primaryKey() -> String? {
return "iTraderCategoryID"
}
}
RealmFile for Skill Data
import Foundation
import Realm
import RealmSwift
#objcMembers class SkillDTO: Object, Codable {
dynamic var iTraderSkillID: String = ""
dynamic var iTraderCategoryID: String = ""
dynamic var vName: String?
enum CodingKeys: String, CodingKey {
case iTraderSkillID = "iTraderSkillId"
case iTraderCategoryID = "iTraderCategoryId"
case vName
}
override static func primaryKey() -> String? {
return "iTraderSkillID"
}
}
Related
I created a UIViewController class with a tableView to show different places in the cells, i'm working with Alamofire and Google API (maps, places), the only problem is that when i run the project the cells are empty, this is my controller class:
import UIKit
class SelectClass: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var list : [QCategoryy] = [QCategoryy]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
self.title = "Categories"
list = NearbyPlaces.getCategories()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
list.sort() { $0.views > $1.views}
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func backTapp(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func doneTapp(_ sender: Any) {
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "CATEGORY_CELL"
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = list[indexPath.row].name
return cell
}
let nearbySearchSegueIdentifier = "goToMcourse"
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: nearbySearchSegueIdentifier, sender: list[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == nearbySearchSegueIdentifier {
guard let category = sender as? QCategoryy else {
return
}
if let vc = segue.destination as? CourseClass2 {
vc.category = category
}
}
}
}
extension QCategoryy {
private static let ketPrefix = "category-"
var views:Int {
get {
return UserDefaults.standard.integer(forKey: QCategoryy.ketPrefix + name)
}
}
func markView() {
UserDefaults.standard.set(views + 1, forKey: QCategoryy.ketPrefix + name)
}
}
and these are the two classes that work with it:
import Foundation
import UIKit
import CoreLocation
import Alamofire
class NearbyPlaces {
static func getCategories() -> [QCategoryy] {
let list:[QCategoryy] = ["Bakery", "Doctor", "School", "Taxi_stand", "Hair_care", "Restaurant", "Pharmacy", "Atm", "Gym", "Store", "Spa"]
return list
}
static let searchApiHost = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
static let googlePhotosHost = "https://maps.googleapis.com/maps/api/place/photo"
static func getNearbyPlaces(by category:String, coordinates:CLLocationCoordinate2D, radius:Int, token: String?, completion: #escaping (QNearbyPlacesResponse?, Error?) -> Void) {
var params : [String : Any]
if let t = token {
params = [
"key" : AppDelegate.googlePlacesAPIKey,
"pagetoken" : t,
]
} else {
params = [
"key" : AppDelegate.googlePlacesAPIKey,
"radius" : radius,
"location" : "\(coordinates.latitude),\(coordinates.longitude)",
"type" : category.lowercased()
]
}
Alamofire.request(searchApiHost, parameters: params, encoding: URLEncoding(destination: .queryString)).responseJSON { response in
if let error = response.error {
completion(nil, error)
}
if let response = QNearbyPlacesResponse(dic : response.result.value as? [String : Any]) {
completion(response, nil)
}
else {
completion(nil, QNearbyPlacesResponseError.noParsingDone)
}
}
}
static func googlePhotoURL(photoReference:String, maxWidth:Int) -> URL? {
return URL.init(string: "\(googlePhotosHost)?maxwidth=\(maxWidth)&key=\(AppDelegate.googlePlacesAPIKey)&photoreference=\(photoReference)")
}
}
enum QNearbyPlacesResponseError : Error {
case noParsingDone
}
struct QNearbyPlacesResponse {
var nextPageToken: String?
var status: String = "NOK"
var places: [QPlace]?
init?(dic:[String : Any]?) {
nextPageToken = dic?["next_page_token"] as? String
if let status = dic?["status"] as? String {
self.status = status
}
if let results = dic?["results"] as? [[String : Any]]{
var places = [QPlace]()
for place in results {
places.append(QPlace.init(placeInfo: place))
}
self.places = places
}
}
func canLoadMore() -> Bool {
if status == "OK" && nextPageToken != nil && nextPageToken?.characters.count ?? 0 > 0 {
return true
}
return false
}
}
and
struct QCategoryy {
var name:String
init(name:String) {
self.name = name
}
}
extension QCategoryy: ExpressibleByStringLiteral {
init(stringLiteral value: String) {
self.name = value
}
init(unicodeScalarLiteral value: String) {
self.init(name: value)
}
init(extendedGraphemeClusterLiteral value: String) {
self.init(name: value)
}
}
it seems to me that it's all right, i can not understand why when i go into my uiviewcontroller the tableView has all the empty cells, here there is also a screen of what i see when running the project
hope someone can find the issue
Try with:
tableView.dataSource = self
Try adding:
tableView.dataSource = self
tableView.delegate = self`
to your viewDidLoad()
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()
}
}
}
I am using library SJSegmentedViewController for my project, github link to pod
Problem:
I have main view controller (FilterVC) on which I have a button "APPLY", on its action I want to access an array stored in another viewcontroller (FilterSkillVC), I am doing this using delegation, but still what I get is an empty instance
UPDATED
MY FilterVC code
import UIKit
import SJSegmentedScrollView
protocol FilterVCDelegate {
func btnApply()
}
class FilterVC: UIViewController {
var selectedSegment: SJSegmentTab?
var segmentedVC : SJSegmentedViewController?
var vcDelegate : FilterVCDelegate?
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
segmentViewInitialization()
}
#IBAction func btnApply(_ sender: Any) {
vcDelegate?.btnApply()
}
}
extension FilterVC {
var titles: [String] {
return [SegmentTitles.skillSet.rawValue,
SegmentTitles.cuisines.rawValue,
SegmentTitles.others.rawValue ]
}
var tabs: [String] {
return [StoryboardId.skillSet.rawValue,
StoryboardId.skillSet.rawValue,
StoryboardId.others.rawValue ]
}
func segmentViewInitialization() {
segmentedVC = CSSegment.setupTabs(storyboard: self.storyboard, tabs: tabs, titles: titles) as? SJSegmentedViewController
segmentedVC?.delegate = self
segmentedVC?.selectedSegmentViewHeight = 2.0
segmentedVC?.segmentTitleColor = .white
segmentedVC?.selectedSegmentViewColor = AppColor.secondary.value
segmentedVC?.segmentBackgroundColor = AppColor.primary.value
segmentedVC?.segmentViewHeight = 64.0
segmentedVC?.segmentShadow = SJShadow.light()
segmentedVC?.segmentTitleFont = AppFont.avenirMedium.size(14.0)
containerView.addSubview((segmentedVC?.view)!)
segmentedVC?.view.frame = containerView.bounds
}
}
extension FilterVC: SJSegmentedViewControllerDelegate {
func didMoveToPage(_ controller: UIViewController, segment: SJSegmentTab?, index: Int) {
if index != tabs.count-1 {
let filterVC = controller as! FilterSkillVC
filterVC.updateCurrentHeader(currentTab:SegmentTitles(rawValue: titles[index])!)
}
if selectedSegment != nil {
selectedSegment?.titleColor(.white)
}
if (segmentedVC?.segments.count)! > 0 {
selectedSegment = segmentedVC?.segments[index]
selectedSegment?.titleColor(AppColor.secondary.value)
}
}
}
My Skill VC code
import UIKit
class FilterSkillVC: UIViewController {
#IBOutlet var tblView: UITableView!
var instance = FilterVC()
lazy var arraySkills = [JSTags]()
lazy var arrayCuisines = [JSTags]()
var arrayID = [String]()
var currentHeader: SegmentTitles = .skillSet
override func viewDidLoad() {
super.viewDidLoad()
apiSkillCall()
apiCuisineCall()
registerCell(cellId: .filterListCell, forTableView: tblView)
tblView.tableFooterView = UIView()
// let instance = FilterVC()
instance.vcDelegate = self
}
func updateCurrentHeader(currentTab : SegmentTitles){
currentHeader = currentTab
tblView.reloadData()
}
//MARK: ----- Custom Methods
func countForHeader() -> NSInteger {
switch currentHeader {
case .skillSet:
return arraySkills.count
case .cuisines:
return arrayCuisines.count
default:
return 0
}
}
func titleForHeader(_ index: NSInteger) -> (name: String?, obj: AnyObject?) {
switch currentHeader {
case .skillSet:
return (name: arraySkills[index].name, obj: arraySkills[index])
case .cuisines:
return (name: arrayCuisines[index].name, obj: arrayCuisines[index])
default:
return (name: nil, obj: nil)
}
}
//MARK: ----- Handle Response Methods
func handleSkillsResponse(response: Response) {
switch response{
case .success(let response):
if let skills = response as? [JSTags] {
self.arraySkills = skills
}
case .failure(let str):
Alerts.shared.show(alert: .oops, message: /str, type: .error)
case .dataNotExist(let str):
Alerts.shared.show(alert: .oops, message: str, type: .info)
}
tblView.reloadData()
}
func handleCuisineResponse(response: Response) {
switch response{
case .success(let response):
if let cuisines = response as? [JSTags] {
self.arrayCuisines = cuisines
tblView.reloadData()
}
case .failure(let str):
Alerts.shared.show(alert: .oops, message: /str, type: .error)
case .dataNotExist(let str):
Alerts.shared.show(alert: .oops, message: str, type: .info)
}
}
//MARK: API Methods
func apiSkillCall() {
APIManager.shared.request(with: ProfileEndPoint.fetchSkills()) { (response) in
self.handleSkillsResponse(response: response)
}
}
func apiCuisineCall() {
APIManager.shared.request(with: ProfileEndPoint.fetchCuisines()) { (response) in
self.handleCuisineResponse(response: response)
}
}
}
extension FilterSkillVC : UITableViewDelegate, UITableViewDataSource, FilterListCellDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countForHeader()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.filterListCell.rawValue) as! FilterListCell
let filter = titleForHeader(indexPath.row)
cell.lblFilterLabel.text = filter.name
//Mark: Cell delegate
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70
}
//Mark: FilterCellDelegate Method
func buttonTapped(cell: FilterListCell) {
if let indexPath = self.tblView.indexPath(for: cell) {
print("Button tapped on row \(indexPath.row)")
if currentHeader == .skillSet {
arraySkills[indexPath.row].isSelected = !arraySkills[indexPath.row].isSelected
}
else {
arrayCuisines[indexPath.row].isSelected = !arrayCuisines[indexPath.row].isSelected
}
}
}
}
extension FilterSkillVC : FilterVCDelegate {
func btnApply() {
for object in arraySkills {
if object.isSelected {
arrayID.append((object.id) ?? "")
}
}
for object in arrayCuisines {
if object.isSelected {
arrayID.append((object.id) ?? "")
}
}
}
}
You are losing the reference to the instance as soon as the viewDidLoad method is completed.
Make instance a global Variable.
Like so :
import UIKit
class FilterSkillVC: UIViewController {
#IBOutlet var tblView: UITableView!
var instance = FilterVC() //New line added here.
lazy var arraySkills = [JSTags]()
lazy var arrayCuisines = [JSTags]()
var arrayID = [String]()
var currentHeader: SegmentTitles = .skillSet
override func viewDidLoad() {
super.viewDidLoad()
apiSkillCall()
apiCuisineCall()
registerCell(cellId: .filterListCell, forTableView: tblView)
tblView.tableFooterView = UIView()
//let instance = FilterVC() //Commented this.
instance.vcDelegate = self
}
More updates :
In the didMoveToPage method, you are getting a reference to a FilterVC (from a storyboard ??), now this instance of FilterVC is different from the instance of filterVC we created.
Please add this change and try :
func didMoveToPage(_ controller: UIViewController, segment: SJSegmentTab?, index: Int) {
if index != tabs.count-1 {
let filterVC = controller as! FilterSkillVC
filterVC.updateCurrentHeader(currentTab:SegmentTitles(rawValue: titles[index])!)
self.vcDelegate = filterVC // <== Updated this line.
}
Requirement : i need to filter the JSON data in UITableView with UISearchBar so i placed UISearchBar (not UISearchBarController) to top of my view controller and i placed UITableView below to the UISearchBarand I also have api key which contains data in json format .
code in my view controller:
class FourthViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UITabBarControllerDelegate,UISearchDisplayDelegate{
var arrDict = NSMutableArray()
var FilteredData = NSMutableArray()
var userid:String!
#IBOutlet var SearchButton: UISearchBar!
#IBOutlet var SlideShow: ImageSlideshow!
#IBOutlet var MyTableView: UITableView!
#IBOutlet var PostButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.hidden = true
SearchButton.delegate = self
jsonParsingFromURL()
SlideShow.backgroundColor = UIColor.whiteColor()
SlideShow.slideshowInterval = 5.0
SlideShow.pageControlPosition = PageControlPosition.UnderScrollView
SlideShow.pageControl.currentPageIndicatorTintColor = UIColor.lightGrayColor()
SlideShow.pageControl.pageIndicatorTintColor = UIColor.blackColor()
SlideShow.contentScaleMode = UIViewContentMode.ScaleAspectFill
SlideShow.setImageInputs(alamofireSource)
}
func jsonParsingFromURL () {
if Reachability.isConnectedToNetwork() == true
{
Alamofire.request(.GET, "http://something.com", parameters: nil, encoding: .URL, headers: nil).response { (req, res, data, error) -> Void in
let dataString = NSString(data: data!, encoding:NSUTF8StringEncoding)
print(dataString)
self.startParsing(data!)
}
}
else{
let alert = UIAlertController(title: "No Internet Connection", message: "make sure your device is connected to the internet", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
func startParsing(data :NSData)
{
let dict: NSDictionary!=(try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
for i in 0 ..< (dict.valueForKey("ads") as! NSArray).count
{
arrDict.addObject((dict.valueForKey("ads") as! NSArray) .objectAtIndex(i))
}
MyTableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrDict.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FirstCell") as! FirstTableViewCell
let strTitle : NSString=arrDict[indexPath.row] .valueForKey("categoryname") as! NSString
let photoImage : NSString=arrDict[indexPath.row] .valueForKey("image1") as! NSString
let SecondImage : NSString=arrDict[indexPath.row] .valueForKey("image2") as! NSString
let ThirdImage : NSString=arrDict[indexPath.row] .valueForKey("image3") as! NSString
let FourthImage : NSString=arrDict[indexPath.row] .valueForKey("image4") as! NSString
let URL_API_HOST2:String = "https://www.imagestring.com/"
// let FourthData = NSData(contentsOfURL: NSURL(string: URL_API_HOST2 + (FourthImage as String))!)
cell.image1.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (photoImage as String)))
cell.image2.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (SecondImage as String)))
// cell.image2.image = UIImage(data: SecData!)
cell.image3.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (ThirdImage as String)))
cell.image4.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (FourthImage as String)))
cell.CategoryName.text = strTitle as String
return cell
}
Issue : I have already loaded one api key which is known as category..now i need fetch subcategory data using search bar..subcategory has another api....
Apple statement : UISearchController object manages the display of search results based on interactions with a search bar. description here
If you'r using UISearchBar
import UIKit
class TDSearchVC: UIViewController ,UITableViewDataSource,UITableViewDelegate , UISearchResultsUpdating , UISearchBarDelegate{
//MARK:- Outlets
//MARK:-
#IBOutlet var tblSearch: UITableView!
//MARK:- Properties
//MARK:-
var dataArray = [String]()
var filteredArray = [String]()
var shouldShowSearchResults = false
var searchController: UISearchController!
//MARK:- VDL
//MARK:-
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
loadListOfCountries() // get the data from file
configureSearchController() // Config Controller in VC
}
//MARK:- VC Methods
//MARK:-
func loadListOfCountries() {
// Specify the path to the countries list file.
let pathToFile = Bundle.main.path(forResource: "Country", ofType: "txt")
if let path = pathToFile {
// Load the file contents as a string.
do{
let countriesString = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
self.dataArray = countriesString.components(separatedBy: "\n")
}
catch{
print("try-catch error is catched!!")
}
tblSearch.reloadData()
}
}
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
self.tblSearch.tableHeaderView = searchController.searchBar
}
//MARK:- table datasource
//MARK:-
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if shouldShowSearchResults {
return filteredArray.count
}
else {
return dataArray.count
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
if shouldShowSearchResults {
cell.textLabel?.text = filteredArray[indexPath.row]
}
else {
cell.textLabel?.text = dataArray[indexPath.row]
}
return cell
}
//MARK:- search update delegate
//MARK:-
public func updateSearchResults(for searchController: UISearchController){
let searchString = searchController.searchBar.text
// Filter the data array and get only those countries that match the search text.
filteredArray = dataArray.filter({ (country) -> Bool in
let countryText: NSString = country as NSString
return (countryText.range(of: searchString!, options: .caseInsensitive).location) != NSNotFound
})
tblSearch.reloadData()
}
//MARK:- search bar delegate
//MARK:-
public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
shouldShowSearchResults = true
tblSearch.reloadData()
}
public func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
shouldShowSearchResults = false
tblSearch.reloadData()
}
}
If you'r using UITextField
import UIKit
class TDSearchVC: UIViewController , UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate{
#IBOutlet var textSearch: UITextField!
#IBOutlet var tblSearchResult: UITableView!
var arrData : [String] = []
var arrFilterData : [String] = []
var isSearch : Bool!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
isSearch = false
/*
* If date Data is in Json then use JSON Serialization
*/
arrData = ["Apple", "Banana", "Chikoo", "Brew", "Cherry", "Mango", "Lotus", "Peacock", "Temple", "Pine Apple","Glass", "Rose", "Church", "Computer", "Carrot"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK:- textfield
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
var searchText = textField.text! + string
if string == "" {
searchText = (searchText as String).substring(to: searchText.index(before: searchText.endIndex))
}
if searchText == "" {
isSearch = false
tblSearchResult.reloadData()
}
else{
getSearchArrayContains(searchText)
}
return true
}
// Predicate to filter data
func getSearchArrayContains(_ text : String) {
var predicate : NSPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", text)
arrFilterData = (arrData as NSArray).filtered(using: predicate) as! [String]
isSearch = true
tblSearchResult.reloadData()
}
// MARK:- TableView Delegates
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if isSearch! {
return arrFilterData.count
}
else{
return arrData.count
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
var cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
if isSearch! {
cell.textLabel?.text = arrFilterData[indexPath.row]
}
else{
cell.textLabel?.text = arrData[indexPath.row]
}
return cell
}
}
I have data in JSON. I'm working with SwiftyJSON. My data is look like this:
[{
"kode_customer": 1,
"nama_customer": "Logam Jaya, UD",
"alamat_customer": "Rajawali No 95",
"kodepos": 60176,
"kode_provinsi": 11,
"gps_lat": -7.233834999999999,
"gps_long": 112.72964666666667
}, {
"kode_customer": 2,
"nama_customer": "Terang, TK",
"alamat_customer": "Raya Dukuh Kupang 100",
"kodepos": 60225,
"kode_provinsi": 11,
"gps_lat": -7.285430000000001,
"gps_long": 112.71538333333335
}, {
"kode_customer": 3,
"nama_customer": "Sinar Family",
"alamat_customer": "By Pass Jomin No 295",
"kodepos": 41374,
"kode_provinsi": 9,
"gps_lat": -6.4220273,
"gps_long": 107.4748978
}, {
"kode_customer": 4,
"nama_customer": "Lancar Laksana, TB",
"alamat_customer": "Jendral Sudirman No 69",
"kodepos": 41374,
"kode_provinsi": 9,
"gps_lat": -6.4220273,
"gps_long": 107.4748978
}]
How to display it on tableView and filter it using UISearchController. Here is my code:
class LocationSearchTable: UITableViewController {
var custData: JSON = []
var filteredData: [String]!
func getCustData() {
let path = NSBundle.mainBundle().pathForResource("cust_toko", ofType: "json")
let jsonData = NSData(contentsOfFile: path!)
let json = JSON(data: jsonData!)
self.custData = son
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")!
cell.textLabel?.text = filteredData[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(filteredData[indexPath.row])
}
}
extension LocationSearchTable: UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
let searchPredicate = NSPredicate(format: "name contains[cd] %#", searchText)
filteredData = JSON(custData.filter{ JSON.Value() })
tableView.reloadData()
}
}
}
It got error like this: 'Value' (aka 'AnyObject') cannot be constructed because it has no accessible initializers
Here is link to github for this question https://github.com/lamfete/MapSearchDemo
First you need to get array from the JSON object with arrayObject after that you need to change your predicate key name to customer_name because there is no key name inside your json response, So change your code like this to only get customer_name from that result.
extension LocationSearchTable: UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
let searchPredicate = NSPredicate(format: "nama_customer contains[cd] %#", searchText)
if let array = custData.arrayObject as? [[String:AnyObject]] {
let filterArr = array.filter{ searchPredicate.evaluateWithObject($0) }
filteredData = filterArr.map({ String($0["nama_customer"])})
tableView.reloadData()
}
}
}
}
I want to answer my own question.
import Foundation
import UIKit
import SwiftyJSON
import MapKit
class LocationSearchTable: UITableViewController {
var custData: JSON = []
var dbTokos : [Toko] = []
var filteredDataToko: [Toko]!
var handleMapSearchDelegate: HandleMapSearch? = nil
var vc = ViewController()
func getCustData() {
let path = NSBundle.mainBundle().pathForResource("cust_toko", ofType: "json")
let jsonData = NSData(contentsOfFile: path!)
let json = JSON(data: jsonData!)
self.custData = Jon
splitData()
}
func splitData() {
for(_, subJson):(String, JSON) in self.custData {
if let name: String = subJson["nama_customer"].stringValue {
if let address: String = subJson["alamat_customer"].stringValue {
if let city: String = subJson["kota"].stringValue {
if let province: String = subJson["provinsi"].stringValue {
if let lat: Double = subJson["gps_lat"].doubleValue {
if let long: Double = subJson["gps_long"].doubleValue {
let toko = Toko(title: name,
locationName: address,
cityName: city,
provinsiName: province,
coordinate: CLLocationCoordinate2D(latitude: lat, longitude: long))
dbTokos.append(toko)
}
}
}
}
}
}
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredDataToko.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")!
cell.textLabel!.text = String(filteredDataToko[indexPath.row].title!)
cell.detailTextLabel!.text = String(filteredDataToko[indexPath.row].locationName) + ", " + String(filteredDataToko[indexPath.row].cityName) + ", " + String(filteredDataToko[indexPath.row].provinsiName)
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let toko = Toko(title: filteredDataToko[indexPath.row].title!,
locationName: filteredDataToko[indexPath.row].locationName,
cityName: filteredDataToko[indexPath.row].cityName,
provinsiName: filteredDataToko[indexPath.row].provinsiName,
coordinate: filteredDataToko[indexPath.row].coordinate)
handleMapSearchDelegate?.dropPinZoomIn(toko)
dismissViewControllerAnimated(true, completion: nil)
}
}
extension LocationSearchTable: UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
filteredDataToko = searchText.isEmpty ? dbTokos : dbTokos.filter(
{
(dataString: Toko) -> Bool in
return dataString.title?.rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
}
)
tableView.reloadData()
}
}
}