I am comparing dates from a file called "file.txt" to put into a tableView as a list. I have a date in the file as the current date as a test at the end. It reads it, but doesn't recognize it as the current date. I have a date formatter setting the format to "MM/dd/yyyy". The checks work correctly with dates before and after the current date being pulled from the phone.
import UIKit
import GoogleMaps
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var banner: UIImageView!
#IBOutlet weak var tableView: UITableView!
var arrayMarkers = [GMSMarker]()
var dictMarkers = [String:String]()
override func viewDidLoad() {
super.viewDidLoad()
banner.image = #imageLiteral(resourceName: "Branding_Iron_Banner")
tableView.estimatedRowHeight = 155.0
tableView.rowHeight = UITableViewAutomaticDimension
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
let currentDate = Date()
print(formatter.string(from: currentDate))
guard let path = Bundle.main.path(forResource: "file", ofType: "txt") else {
print("File wasn't found")
return
}
let filemgr = FileManager()
if filemgr.fileExists(atPath: path) {
print("Found the file to read from!")
}
guard let streamReader = StreamReader(path: path) else {
print("Dang! StreamReader couldn't be created!")
return
}
var lineCounter = 0
var lat = 0.0
var log = 0.0
var address = ""
var date = ""
var time = ""
var snip = ""
var snip2 = ""
var same = true
while !streamReader.atEof {
guard let nextLine = streamReader.nextLine() else {
print("Oops! Reached the end before printing!")
break
}
if(lineCounter % 5 == 0) {
lat = (nextLine as NSString).doubleValue
}
else if(lineCounter % 5 == 1) {
log = (nextLine as NSString).doubleValue
}
else if(lineCounter % 5 == 2) {
address = nextLine
}
else if(lineCounter % 5 == 3) {
date = nextLine
let fileDate = formatter.date(from: date)
if (currentDate.compare(fileDate!) == .orderedSame) {
snip2 = date
print("Same dates compare with current: \(String(describing: fileDate))")
same = true
}
if(fileDate?.compare(currentDate) == .orderedDescending) {
print("Date comes after current: \(String(describing: fileDate))")
snip2 = date
same = true
}
if(fileDate?.compare(currentDate) == .orderedAscending) {
same = false
}
}
else if(lineCounter % 5 == 4){
if(same == true) {
time = nextLine
let position = CLLocationCoordinate2DMake(lat, log)
let marker = GMSMarker(position: position)
marker.title = address
snip = snip2 + "\n"+time
marker.snippet = snip
arrayMarkers.append(marker)
print("\n\(String(describing: marker.title))")
same = false
}
}
lineCounter += 1
print("\(lineCounter): \(nextLine)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayMarkers.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 2
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
//print("Inside the assigning of table cells")
let marker = arrayMarkers[indexPath.row]
//print(marker.snippet!)
cell.textLabel?.text = marker.title
cell.detailTextLabel?.text = marker.snippet
return cell
}
}
The date I care about from my file is formatted as "06/07/2018" as is the format for the rest of my dates in my file.
Updated with output comparison:
74: 05/30/2018
75: 8:00 am to 5:00 pm
76: 41.313000
77: -105.576195
78: 1513 Fraternity Row
The current date is: 2018-06-08 15:32:22 +0000
The file date is: Optional(2018-06-08 06:00:00 +0000)
It is supposed to be ignoring the time after the formatting.
The issue is that compare on two Date instances compares down to the microsecond.
Your line let currentDate = Date() gives you an exact moment of "now" to the microsecond.
As you read the file and create a Date from the "MM/dd/yy" string, you get a Date to the microsecond of midnight local time on the given date.
So even if the two dates are on the same day, one is the current time and one is midnight local time.
With that explanation of why it isn't working out of the way, here's the simple fix. Update your comparison code to the following:
if Calendar.current.isDate(currentDate, inSameDayAs: fileDate!) {
snip2 = date
print("Same dates compare with current: \(String(describing: fileDate))")
same = true
} else if currentDate < fileDate! {
print("Date comes after current: \(String(describing: fileDate))")
snip2 = date
same = true
} else {
// Not the same or descending so it must be ascending
same = false
}
Related
I use the realm database for my application (to-do list), everything works fine, BUT once I flew to another country and noticed that the records in the database are empty (the application gives out an empty list), upon arrival back to my country everything returned to normal ... Now I am again in a different country and the situation repeats again (database is empty), for some reason the database gives an empty list result, can you please explain why this is happening and how to fix that?
Output example
var dbToDoList = DBrealmToDoList()
var arrayToDoList: Results<RealmToDoList> {
get {
return dbToDoList.getArray()
}
}
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
dbToDoList.realm = realm
let current = arrayToDoList.filter { (_todo) -> Bool in
return _todo.date == date
}.first
self.selectedDate = date
if current != nil {
self.selectedLists = current?.lists
self.selectedListsSorted = self.selectedLists?.sorted(by: { (val, val2) -> Bool in
return (!val.value && val2.value)
})
}
}
And then in tableView I display the data from the selectedListsSorted
// MARK: UITableView
extension ToDoListViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedListsSorted?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ToDoListTableViewCell
let current = selectedListsSorted?[indexPath.row]
cell.nameLabel.text = current?.key
cell.checkBox.isSelected = current?.value ?? false
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90
}
}
Here is a class for working with db
class RealmToDoList: Object {
#objc private dynamic var dictionaryData: Data?
var lists: [String: Bool] {
get {
guard let dictionaryData = dictionaryData else {
return [String: Bool]()
}
do {
let dict = try JSONSerialization.jsonObject(with: dictionaryData, options: []) as? [String: Bool]
return dict!
} catch {
return [String: Bool]()
}
}
set {
do {
let data = try JSONSerialization.data(withJSONObject: newValue, options: [])
dictionaryData = data
} catch {
dictionaryData = nil
}
}
}
#objc dynamic var date : Date?
}
class DBrealmToDoList {
var realm: Realm!
func write(_ data: RealmToDoList) throws -> Bool {
var result = false
if (realm != nil) {
try! realm.write {
realm.add(data)
result = true
}
return result
} else {
throw RuntimeError.NoRealmSet
}
}
func getArray() -> Results<RealmToDoList> {
return realm.objects(RealmToDoList.self)
}
func delete(_ data: RealmToDoList) throws -> Bool {
var result = false
if (realm != nil) {
try! self.realm.write {
self.realm.delete(data)
result = true
}
return result
} else {
throw RuntimeError.NoRealmSet
}
}
func update(ofType:Object,value:AnyObject,key:String)->Bool{
do {
let realm = try Realm()
try realm.write {
ofType.setValue(value, forKeyPath: key)
}
return true
}catch let error as NSError {
fatalError(error.localizedDescription)
}
}
func filter(id:Int) -> RealmToDoList? {
let match = realm.objects(RealmToDoList.self).filter("id == %#",id).first
return match
}
func newToDoList(date : Date?,lists: [String: Bool]) -> RealmToDoList{
let pill = RealmToDoList()
pill.date = date
pill.lists = lists
return pill
}
}
I doubt that the matter is in the database, but I cannot understand what it is, because I don’t do a filter by country, etc.
The issue is the date because the date will change based on time zone and if you're selecting today's date/time in one time zone, it will be different that's what's in the database. So if a filter is based on this date
#objc dynamic var date : Date?
then that date will be "today" for whatever time zone you're in but a "today" date that was created this morning in a different time zone will not return the current time zones date.
e.g. if you create a new date/time it will be today in this timezone but could be yesterday in a different time zone.
So using I am Alamofire and SwiftyJSON I am able to pull data from a JSON source and assign it to a tableview. What I need to do now is filter the results by date. The idea is to grab todays date and only show items that equal or are greater than todays date.
Using Alamofire now when I query the source I get the following
{
"mlb_schedule": {
"columns": [
"awayTeam",
"homeTeam",
"date",
"time"
],
"records": [
[
"TOR",
"BOS",
"7/14/18",
""
],
[
"KCA",
"CHA",
"7/14/18",
""
],
[
"TBA",
"MIN",
"7/14/18",
""
],
[
"MIL",
"PIT",
"7/14/18",
""
],
[
"ARI",
"ATL",
"7/14/18",
""
],
I created a getDate function to pull the current date and send. it to the var dateToday in the code below. Where my issue is exists in Alamofire where I can't seem to select the dict value to filter by the response as shown in the code below.
var arrRes = [Any]()
public var baseballSelectedRow: [String] = []
var dateToday = ""
override func viewDidLoad() {
super.viewDidLoad()
getDate()
//Alamofire
Alamofire.request("http://52.34.250.4/mlb/api.php/mlb_schedule").responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar["mlb_schedule"]["records"].arrayObject {
self.arrRes = resData.filter { $0.dict[2] <= dateToday}
}
if self.arrRes.count > 0 {
self.tableView.reloadData()
}
}
}
}
func getDate() {
let currentDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
let convertableDate = dateFormatter.string(from: currentDate)
dateToday = convertableDate
}
}
extension SwarmBaseballViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrRes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "SwarmListTableViewCell") as? SwarmListTableViewCell {
if let dict = arrRes[indexPath.row] as? [Any] {
if dict.count > 2 {
cell.awayLabel?.text = dict[0] as? String
cell.homeLabel?.text = dict[1] as? String
cell.dateLabel?.text = dict[2] as? String
cell.timeLabel?.text = dict[3] as? String
}
}
return cell
} else {
return SwarmListTableViewCell()
}
}
I realize my syntax is wrong but, can't for the life of me find how/why?
I have a model object being returned in JSON from Firebase.
{
"id": 1,
"name": "Jon Doe",
"time": ["1525592246"]
},
{
"id": 2,
"name": "Jane Doe",
"time": ["1525592266"]
},
I would like to structure these objects into sections in a UITableView based on the below:
enum DiarySectionType {
case Today
case Tomorrow
case ThisWeek
case ThisMonth
case Later
}
I.e If a "time" is today it will be in the today section of the UITableView
What is the best way to approach this? I've thought of having separate arrays for each. But don't think that's the way to go.
As always any help appreciated.
First you need helper extension for your Date
extension Date {
public func component(_ component: Calendar.Component) -> Int {
let calendar = Calendar.autoupdatingCurrent
return calendar.component(component, from: self)
}
public var isToday: Bool {
let calendar = Calendar.autoupdatingCurrent
return calendar.isDateInToday(self)
}
public var isTomorrow: Bool {
let calendar = Calendar.autoupdatingCurrent
return calendar.isDateInTomorrow(self)
}
public var isThisWeek: Bool {
return isInSameWeek(date: Date())
}
public var isThisMonth: Bool {
return isInSameMonth(date: Date())
}
public var islater: Bool {
return isInSameMonth(date: Date()) ? false : true
}
}
extension Date {
func isInSameWeek(date: Date) -> Bool {
return Calendar.current.isDate(self, equalTo: date, toGranularity: .weekOfYear)
}
func isInSameMonth(date: Date) -> Bool {
return Calendar.current.isDate(self, equalTo: date, toGranularity: .month)
}
}
Then your Enum
enum DiarySectionType:Int{
case Today
case Tomorrow
case ThisWeek
case ThisMonth
case Later
case count // use for number of section
init (with date:Date){
if date.isToday {
self = .Today
}else if date.isTomorrow{
self = .Tomorrow
}else if date.isThisWeek{
self = .ThisWeek
}else if date.isThisMonth{
self = .ThisMonth
}else{
self = .Later
}
}
}
Your data Formalize as you need
struct Item{
var id : Int
var name : String
var time : Double
init(id:Int, name:String,time:Double) {
self.id = id
self.name = name
self.time = time
}
}
// Controller
class ViewController: UIViewController{
var data = [Item]() // your data before sections
var dataWork = [DiarySectionType: [Item]]() // date After sections
override func viewDidLoad() {
super.viewDidLoad()
self.sortData()
}
// When generating sorted table data we can easily use our TableSection to make look up simple and easy to read.
func sortData() {
dataWork[.Today] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time)) == .Today })
dataWork[.Tomorrow] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time)) == .Tomorrow })
dataWork[.ThisWeek] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time)) == .ThisWeek })
dataWork[.ThisMonth] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time)) == .ThisMonth })
dataWork[.Later] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time)) == .Later })
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
// As long as `count` is the last case in our TableSection enum,
// this method will always be dynamically correct no mater how many table sections we add or remove.
func numberOfSections(in tableView: UITableView) -> Int {
return DiarySectionType.count.rawValue
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Using Swift's optional lookup we first check if there is a valid section of table.
// Then we check that for the section there is data that goes with.
if let tableSection = DiarySectionType(rawValue: section), let data = dataWork[tableSection] {
return data.count
}
return 0
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
var title : String = ""
if let tableSection = DiarySectionType(rawValue: section) {
switch tableSection {
case .Today:
title = "Today"
case .Tomorrow:
title = "Tomorrow"
case .ThisMonth:
title = "ThisMonth"
case .ThisWeek:
title = "ThisWeek"
case .Later:
title = "Later"
default:
title = ""
}
}
return title
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
// Similar to above, first check if there is a valid section of table.
// Then we check that for the section there is a row.
if let tableSection = DiarySectionType(rawValue: indexPath.section), let item = dataWork[tableSection]?[indexPath.row] {
// use item item
}
return cell
}
}
at first sorry for my bad english.
My problem is that my tableview will be misrepresented as soon as I save a new file in Firebase.
When saving, a new AddViewController is called.
After saving is automatically returned to the TableviewController.
However, if I stop and restart the app so that the TableviewController is recreated, my tableview will be displayed correctly.
I create a header from an array.
Then I create the cell from another array.
I do not understand why my tableview is displayed incorrectly when I return after saving, but when I recreate the view after the app has finished everything is shown correctly.
My sample pictures:
that's right:
that's bad
My Code from TableViewController:
override func viewDidLoad() {
super.viewDidLoad()
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
refresher.addTarget(self, action: #selector(TagebuchViewController.refresh), for: UIControlEvents.valueChanged)
tableView.addSubview(refresher)
loadTableview()
}
Load data from Firebase, loadTableView():
func loadTableview(){
let userID = Firebase.Auth.auth().currentUser?.uid
databaseRef = Database.database().reference().child("DiabetesIOS").child(userID!)
databaseRef.observe(.value, with: {(snapshot) in
var newItems = [Post]()
var newItemsDate = [String]()
var aNewTime = [String]()
var aNewBl = [String]()
var aNewK = [String]()
var aNewBo = [String]()
var aNewBa = [String]()
var aNewBlu = [String]()
var aNewP = [String]()
var aNewN = [String]()
var dimArrayNewTime = [[String]]()
var dimArrayNewBl = [[String]]()
var dimArrayNewK = [[String]]()
var dimArrayNewBo = [[String]]()
var dimArrayNewBa = [[String]]()
var dimArrayNewBlu = [[String]]()
var dimArrayNewP = [[String]]()
var dimArrayNewN = [[String]]()
for year in snapshot.children.allObjects as! [DataSnapshot] {
for month in year.children.allObjects as! [DataSnapshot] {
for day in month.children.allObjects as! [DataSnapshot] {
for date in day.children.allObjects as! [DataSnapshot] {
for time in date.children.allObjects as! [DataSnapshot] {
let newPost = Post(snapshot: time)
newItems.append(newPost)
let newDate = Post(snapshot: time)
newItemsDate.append(newDate.snap6Date!)
if self.snapshotCheck == 0{
self.snapshotCheckDate = newDate.snap6Date
self.snapshotCheck += 1
}
else{
}
if self.snapshotCheckDate == newDate.snap6Date{
aNewTime.append(newDate.time)
aNewBl.append(newDate.blutzucker)
aNewKe.append(newDate.ke)
aNewBo.append(newDate.bolusInsulin)
aNewBa.append(newDate.basalInsulin)
aNewBlu.append(newDate.blutdruck)
aNewP.append(newDate.puls)
aNewN.append(newDate.notiz)
}
else{
dimArrayNewTime.append(aNewTime)
dimArrayNewBl.append(aNewBlutzucker)
dimArrayNewK.append(aNewKe)
dimArrayNewBo.append(aNewBolusinsulin)
dimArrayNewBa.append(aNewBasalinsulin)
dimArrayNewBlu.append(aNewBlutdruck)
dimArrayNewP.append(aNewPuls)
dimArrayNewN.append(aNewNotiz)
aNewTime.removeAll()
aNewBl.removeAll()
aNewK.removeAll()
aNewBo.removeAll()
aNewBa.removeAll()
aNewBlu.removeAll()
aNewP.removeAll()
aNewN.removeAll()
aNewTime.append(newDate.time)
aNewBl.append(newDate.blutzucker)
aNewK.append(newDate.ke)
aNewBo.append(newDate.bolusInsulin)
aNewBa.append(newDate.basalInsulin)
aNewBlu.append(newDate.blutdruck)
aNewP.append(newDate.puls)
aNewN.append(newDate.notiz)
self.snapshotCheckDate = newDate.snap6Date
}
}
}
}
}
}
self.postArrayValue = newItems
self.aHeaderDate = newItemsDate
self.aHeaderDate = self.uniq(source: self.aHeaderDate)
dimArrayNewTime.append(aNewTime)
dimArrayNewBl.append(aNewBl)
dimArrayNewK.append(aNewK)
dimArrayNewBo.append(aNewBo)
dimArrayNewBa.append(aNewBa)
dimArrayNewBlu.append(aNewBlu)
dimArrayNewP.append(aNewP)
dimArrayNewN.append(aNewN)
self.dimArrayTime = dimArrayNewTime
self.dimArrayBl = dimArrayNewBl
self.dimArrayK = dimArrayNewK
self.dimArrayBo = dimArrayNewBo
self.dimArrayBa = dimArrayNewBa
self.dimArrayBlu = dimArrayNewBlu
self.dimArrayP = dimArrayNewP
self.dimArrayN = dimArrayNewN
newItems.removeAll()
newItemsDate.removeAll()
aNewTime.removeAll()
aNewBl.removeAll()
aNewK.removeAll()
aNewBo.removeAll()
aNewBa.removeAll()
aNewBlu.removeAll()
aNewP.removeAll()
aNewN.removeAll()
dimArrayNewTime.removeAll()
dimArrayNewBl.removeAll()
dimArrayNewK.removeAll()
dimArrayNewBo.removeAll()
dimArrayNewBa.removeAll()
dimArrayNewBlu.removeAll()
dimArrayNewP.removeAll()
dimArrayNewN.removeAll()
self.tableView.reloadData()
}){
(error) in
print(error.localizedDescription)
}
}
For my Header:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = Bundle.main.loadNibNamed("TableViewCell1", owner: self, options: nil)?.first as! TableViewCell1
headerView.date.text = aHeaderDate[section]
headerView.backgroundColor = UIColor.white
return headerView
}
NumberOfRows:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dimArrayTime[section].count
}
Number of Headers:
override func numberOfSections(in tableView: UITableView) -> Int {
return aHeaderDate.count
}
Number of Cells:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dimArrayTime[section].count
}
Section:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell2 = Bundle.main.loadNibNamed("TableViewCell2", owner: self, options: nil)?.last as! TableViewCell2
let sectionTime = dimArrayTime[indexPath.section][indexPath.row]
let sectionBl = dimArrayBl[indexPath.section][indexPath.row]
let sectionK = dimArrayK[indexPath.section][indexPath.row]
let sectionBo = dimArrayBo[indexPath.section][indexPath.row]
let sectionBa = dimArrayBa[indexPath.section][indexPath.row]
let sectionBlu = dimArrayBlu[indexPath.section][indexPath.row]
let sectionP = dimArrayP[indexPath.section][indexPath.row]
let sectionN = dimArrayN[indexPath.section][indexPath.row]
cell2.time.text = sectionTime
cell2.bl.text = sectionBl
cell2.k.text = sectionK
cell2.bo.text = sectionBo
cell2.ba.text = sectionBa
cell2.blu.text = sectionBlu
cell2.p.text = sectionP
cell2.n.text = sectionN
return cell2
}
addViewController:
#IBAction func saveInDatabaseFirebase(_ sender: Any) {
let userID = Firebase.Auth.auth().currentUser?.uid
let postRef = dataRef.child("DIOS").child(userID!).child(stringForDbYear).child(stringForDbMonth).child(stringForDbDay).child(stringForDbDate).child(stringForDbTime)
sDate = tFDate.text!
if tFBl.text == "" {
sBl = "-"
}
else{
sBl = tFBl.text!
}
if tFK.text == "" {
sK = "-"
}
else{
sK = tFK.text!
}
if tFBo.text == "" {
sBo = "-"
}
else{
sBo = tFBo.text!
}
if tFBa.text == "" {
sBa = "-"
}
else{
sBa = tFBa.text!
}
if tfBlu.text == "" {
sBlu = "-"
}
else{
sBlu = tfBlu.text!
}
if tFP.text == "" {
sP = "-"
}
else{
sP = tFP.text!
}
if tFN.text == "" {
sN = "-"
}
else{
sN = tFN.text!
}
let post = Post (date: stringForDbDate, time: stringForDbTime, day: stringForDbDay, bl: sBl, k: sK, bo: sBo, ba: sBa, blu: sBlu, p: sP, n: sN, snap1DIOS: "DIOS", snap2UserID: userID!, snap3Year: stringForDbYear, snap4Month: stringForDbMonth, snap5Day: stringForDbDay, snap6Date: stringForDbDate, snap7Time: stringForDbTime)
postRef.setValue(post.toAnyObject())
self.dismiss(animated: true, completion: nil);
}
Thank you very much for help
I am making an app for smartsearch. I have implemented through making parameters into string then append the strings.Then for search i am implementing filter to search from the search. But its getting lengthy. I want it in compact using NSPredicate.
My code is here. Can anyone make it using NSPredicate and NSCompoundPredicate
import UIKit
struct Request{
var type:String!
var firstName:String!
var lastName:String!
var combineString:String {
get {
let text = "\(self.type!) \(self.firstName) \(self.lastName)"
return text
}
}
init() {
self.type = ""
self.firstName = ""
self.lastName = ""
}
init(_ type:String,_ firstName:String,_ lastName:String) {
self.type = type
self.firstName = firstName
self.lastName = lastName
}}
class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet var searchbar:UISearchBar!
#IBOutlet var headline:UILabel!
#IBOutlet var table:UITableView!
var type:Array = [String]()
var firstName:Array = [String]()
var lastName:Array = [String]()
var tempResults = Array<[Request]>()
var requestArray = Array<Request>()
var filteredArray = Array<Request>()
var isSearching = false
type = [“4343”, “45450”, “68468”, “4686”, “56461”, “48661”]
firstName = [“Tom”, “Michel”, “Steve”, “Rahul”, “Iswar”, “Kuldeep”]
lastName = [“Moody”, “Clark”, “Smith”, “Kumar”, “Pandey”, “Yadav”]
for i in 0..<requestTypeArr.count {
let type = self.type[i]
let firstName = self.firstName[i]
let lastName = self.lastName[i]
var request = Request()
request.type = type
request.firstName = firstName
request.lastName = lastName
self.requestArray.append(request)
}
let string = String(format: "Total list No %ld", self.requestArray.count)
self.headline.text = string
self.table.delegate = self
self.table.dataSource = self
self.table.contentInset = UIEdgeInsets(top: 44, left: 0, bottom: 0, right: 0)
self.table.estimatedRowHeight = 44
self.table.rowHeight = UITableViewAutomaticDimension
self.searchbar.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.isSearching == true {
return self.filteredArray.count
}
return self.requestArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RquestDetailTableViewCell") as! RquestDetailTableViewCell
var request = self.requestArray[indexPath.row]
if self.isSearching == true {
request = self.filteredArray[indexPath.row]
}
cell.type.text = request.type
cell.firstName.text = request.firstName
cell.lastName.text = request.lastName
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}}
extension ViewController : UISearchBarDelegate {
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.isSearching = true
// self.table.reloadSections([0], with: .automatic)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
//Filter one
//print("Search Query:- \(searchText)")
if searchText.components(separatedBy: .whitespaces).joined(separator: "").characters.count == 0 {
if self.isSearching == true {
self.isSearching = false
self.filteredArray = Array<Request>()
self.tempResults = Array<[Request]>()
}
}else {
if self.isSearching == false {
self.isSearching = true
}
var temp = Array<Request>()
if self.tempResults.count == 0 {
temp = self.requestArray.filter({ (object) -> Bool in
//print("\nSearch Text = \(searchText.lowercased()) \nand Source Combine String = \(object.combineString.lowercased())")
let lowercaseInput = searchText.lowercased()
let lowercaseSource = object.combineString.lowercased()
let sourceComponents = lowercaseSource.components(separatedBy: .whitespaces)
let inputComponents = lowercaseInput.components(separatedBy: .whitespaces)
let sourceSet = Set(sourceComponents)
var inputSet = Set(inputComponents)
if let index = inputSet.index(of: ""){
_ = inputSet.remove(at: index)
}
var filtered = [String]()
inputSet.forEach({ (word) in
let temp = sourceSet.filter({$0.contains(word)})
//let temp2 = sourceSet.filter({$0.hasPrefix(word)})
filtered.append(contentsOf: temp)
// let temp2 = sourceSet.filter({$0.hasPrefix(word)})
//filtered.append(contentsOf: temp2)
})
let set = Set(filtered)
var isOK = set.isSubset(of: sourceSet)
if set.count == 0 {
isOK = false
}
return isOK
})
self.filteredArray = temp
}else {
if let last = self.tempResults.last {
temp = last.filter({ (object) -> Bool in
let lowercaseInput = searchText.lowercased()
let lowercaseSource = object.combineString.lowercased()
let lastInputWord = lowercaseInput.components(separatedBy: .whitespaces).last!
let sourceComponents = lowercaseSource.components(separatedBy: .whitespaces)
let inputComponents = [lastInputWord]
let sourceSet = Set(sourceComponents)
let inputSet = Set(inputComponents)
var filtered = [String]()
inputSet.forEach({ (word) in
let temp = sourceSet.filter({$0.contains(word)})
//let temp2 = sourceSet.filter({$0.hasPrefix(word)})
filtered.append(contentsOf: temp)
})
let set = Set(filtered)
var isOK = set.isSubset(of: sourceSet)
if set.count == 0 {
isOK = false
}
return isOK
})
self.filteredArray = temp
}
}
}
self.table.reloadSections([0], with: .automatic)
}
func searchBar(_ searchBar: UISearchBar, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == " " {
self.tempResults.append(self.filteredArray)
}
if range.length == 1 {
//Handle Backspace/delete
let string = searchBar.text! as NSString
let temp = string.substring(with: range) as String
let newRange = string.range(of: temp, options: .backwards)
let newText = string.replacingCharacters(in: newRange, with: "")
let words = newText.components(separatedBy: .whitespaces).count
if words > 1 {
print("word count = \(words)")
let count = self.tempResults.count
if count > words {
self.tempResults.removeLast()
}
}else {
self.tempResults = Array<[Request]>()
}
}
return true
}
}