Using UISearchbar with JSON to filter the result - swift

I am fetching the data from JSON using http in the following code:
I have an ObjectModel, DownloadModelProtocol, and TableViewController
(Modal.swift)
class OrderItemModal: NSObject {
var deptname: String!
var staffname: String!
var status: String!
var userid: String!
}
(DownloadOrderModal.swift):
protocol OrderDownloadProtocol: class {
func itemsDownload(items: Array<Any>)
}
...
let bmsOrders = NSMutableArray()
...
weak var delegate: OrderDownloadProtocol!
let urlPath = "http://localhost/production/api/db_orders.php"
func downloadItems() {
let url = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
...
for i in 0..<jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let bmsOrder = OrderItemModal()
....
bmsOrders.add(bmsOrder)
....
declaration:
var orderItems = [OrderItemModal]()
var filterArray= [OrderItemModal]()
func itemsDownload(items: Array<Any>) {
orderItems = items as! [OrderItemModal]
}
and viewDidLoad:
let bmsOrder = DownloadOrderModal()
bmsOrder.delegate = self
bmsOrder.downloadItems()
this is the JSON result:
(
{
"deptname" = "Production";
"staffname" = Warehouse;
"status" = 1;
"userid" = ware;
})
This the the search bar code
filterArray = orderItems.filter( { ($0. staffname) (of: searchText, options: .caseInsensitive) })
And finally, this is the error:
Cannot assign value of type '[OrderItemModal]' to type '[String]'
Ultimately, I will populate the data into a table.

You have a few issues. It seems that orderItems is an NSArray array of OrderItemModal values. The first thing you need to do is to stop using NSArray and use a Swift array of the proper type. In this case it should be [OrderItemModal]. You will need to ensure filterArray is also declared as [OrderItemModal].
The result of a filter on such an array will be an array of OrderItemModal but you are attempting to force cast the result as an array of String.
You are also force-casting the closure to be (Any) -> Bool. There's no need for that.
And lastly, you are needlessly using NSString. Stick with String.
All you need is:
filterArray = orderItems.filter { (item) -> Bool in
return item.staffname.range(of: searchText, options: .caseInsensitive) != nil
}
Even simpler:
filterArray = orderItems.filter { $0.staffname.range(of: searchText, options: .caseInsensitive) != nil }

Related

How convert Realm data to Json on Swift? Realm version 10.11.0

until version 10.7.6 of Realm I could convert to dictionary and then to json with this code below, but the ListBase class no longer exists.
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValues(forKeys: properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeys(dictionary)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase { /*Cannot find type 'ListBase' in scope*/
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as! Object
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name as NSCopying)
}
}
return mutabledic
}
}
let parameterDictionary = myRealmData.toDictionary()
guard let postData = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else {
return
}
List now inherits from RLMSwiftCollectionBase apparently, so you can check for that instead. Also, this is Swift. Use [String: Any] instead of NSDictionary.
extension Object {
func toDictionary() -> [String: Any] {
let properties = self.objectSchema.properties.map { $0.name }
var mutabledic = self.dictionaryWithValues(forKeys: properties)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic[prop.name] = nestedObject.toDictionary()
} else if let nestedListObject = self[prop.name] as? RLMSwiftCollectionBase {
var objects = [[String: Any]]()
for index in 0..<nestedListObject._rlmCollection.count {
let object = nestedListObject._rlmCollection[index] as! Object
objects.append(object.toDictionary())
}
mutabledic[prop.name] = objects
}
}
return mutabledic
}
}
Thanks to #Eduardo Dos Santos. Just do the following steps. You will be good to go.
Change ListBase to RLMSwiftCollectionBase
Change _rlmArray to _rlmCollection
Import Realm

How to data pass array to dictionary in Alamofire

my json response array to dictioary but i am tring to get my data in show tableview.but my response in one key "member" and i want get data for a member key but getting some error.
I am trying to pass an array as a parameter to a Alamofier request .but i have not get data from my json i am getting some error my code i can not what i do....
My URL:
https://myfoodtalk.com:3001/api/restaurants?filter={"counts":"restaurant-comments","order":"created DESC","include":[{"relation":"follow-restaurants","scope":{"where":{"m_id":""}}},{"relation":"members"},{"relation":"favorite-restaurants","scope":{"where":{"m_id":""}}}]}
My model class:
class RestaurantsData: NSObject {
var title = String()
var descriptions = String()
var image1 = String()
var postcommentsCount = String()
var viewscount = String()
var created = String()
var members = [String:Any]()
var mbersdata = membersData()
func getRestaurentData(dataArray: [[String:Any]]) -> [RestaurantsData] {
var array = [RestaurantsData]()
let mObj = membersData()
for item in dataArray {
let obj = RestaurantsData()
obj.title = item.validatedValue("title", expected: String() as AnyObject) as! String
obj.descriptions = item.validatedValue("description", expected: String() as AnyObject) as! String
obj.image1 = item.validatedValue("image1", expected: String() as AnyObject) as! String
obj.postcommentsCount = item.validatedValue("post-commentsCount", expected: String() as AnyObject) as! String
obj.viewscount = item.validatedValue("views_count", expected: String() as AnyObject) as! String
obj.created = item.validatedValue("created", expected: String() as AnyObject) as! String
obj.members = item.validatedValue("members", expected: [String:Any]() as AnyObject) as! [String:Any]
obj.mbersdata = mObj.getMemberData(dataDic:obj.members)
array.append(obj)
}
return array
}
//Mark:- Class created for member data
class membersData: NSObject {
var photo = String()
var created = String()
var username = String()
func getMemberData(dataDic: [String:Any]) -> membersData {
let obj = membersData()
obj.username = dataDic.validatedValue("username", expected: String() as AnyObject) as! String
obj.created = dataDic.validatedValue("created", expected: String() as AnyObject) as! String
obj.photo = dataDic.validatedValue("photo", expected: String() as AnyObject) as! String
return obj
}
}
}
My code:- I'm using Alamofire
var dataArray = [RestaurantsData]()
//MARK: Web API calling
func ShowRestaurantsData(){
var params = [String:Any]
params = [
"counts":"restaurant-comments",
"order":"created DESC",
"include":[["relation":"follow-restaurants","scope":["where":["m_id":""]]],["relation":"members"],["relation":"favorite-restaurants","scope":["where":["m_id":""]]]
Alamofire.request( "https://myfoodtalk.com:3001/api/restaurants", method:.get, parameters: nil, headers: nil).responseJSON { (responseObject) -> Void in
switch responseObject.result
{
case .success(let value):
let dataArray = value as! [[String:Any]]
print("JSON Response:::::: \(dataArray)")
let obj = RestaurantsData()
self.dataArray = obj.getRestaurentData(dataArray: dataArray)
self.tableView.reloadData()
case .failure(let error):
print(error)
}
}
}
In your request,
Alamofire.request( "https://myfoodtalk.com:3001/api/restaurants", method:.get, parameters: nil, headers: nil).responseJSON { (responseObject) -> Void in
You are passing "
parameters as nil
which is wrong, pass "params"...

Swift SearchBar cannot filter data

I have setup UISearchBar things. but I'm getting error says.
Cannot assign value of type '[cellData]' to type '[String]'
here's the code
struct cellData {
let jobTitle : AnyObject?
let companyName : String?
let jobLocation : String?
let jobDescription : String?
let jobReq : String?
let firstPosterImage : AnyObject?
let secondPosterImage : AnyObject?
let createdAt : Date
init(jobTitle: AnyObject?, companyName: String? = nil, jobLocation: String? = nil ,jobDescription: String? = nil, jobReq:String? = nil, firstPosterImage: AnyObject? = nil, secondPosterImage: AnyObject? = nil, timeStamp:Double) {
self.jobTitle = jobTitle
self.companyName = companyName
self.jobLocation = jobLocation
self.jobDescription = jobDescription
self.jobReq = jobReq
self.firstPosterImage = firstPosterImage
self.secondPosterImage = secondPosterImage
self.createdAt = Date(timeIntervalSince1970: timeStamp/1000)
}
}
var cellDataArray = [cellData]()
var filtered = [String]()
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
isSearching = false
tableView.reloadData()
} else {
isSearching = true
filtered = cellDataArray.filter({($0.jobTitle?.lowercased?.contains(searchText.lowercased()))!})
tableView.reloadData()
}
}
I'm getting error in this line
filtered = cellDataArray.filter({($0.jobTitle?.lowercased?.contains(searchText.lowercased()))!})
. notice that CellDataArray has the struct of cellData.
and I'm using searchBar in tableView.
Thanks.
Your problem is that cellDataArray and filtered are of 2 different data types ( String and struct CellData ) so you can't simply assign one to the other without a conversion like
let res = cellDataArray.filter({($0.jobTitle?.lowercased?.contains(searchText.lowercased()))!})
filtered = res.map { $0.anyProprtyInside } // property should be a String
What you may mean is to declare filtered as
var filtered = [CellData]() // start structs / classes / protocols with uppercase letter

Cannot convert value of type 'String?!' to expected argument type 'Notifications'

I am trying to check the id of a record before I put it into the array, using xcode swift
here is the code. But, i get the following error
Notifications.swift:50:46: Cannot convert value of type 'String?!' to expected argument type 'Notifications'
on this line
*if (readRecordCoreData(result["MessageID"])==false)*
Please can some one help to explain this error
import CoreData
struct Notifications{
var NotifyID = [NSManagedObject]()
let MessageDesc: String
let Messageid: String
init(MessageDesc: String, Messageid:String) {
self.MessageDesc = MessageDesc
self.Messageid = Messageid
// self.MessageDate = MessageDate
}
static func MessagesWithJSON(results: NSArray) -> [Notifications] {
// Create an empty array of Albums to append to from this list
var Notification = [Notifications]()
// Store the results in our table data array
if results.count>0 {
for result in results {
//get fields from json
let Messageid = result["MessageID"] as! String
let MessageDesc = result["MessageDesc"] as? String
let newMessages = Notifications(MessageDesc: MessageDesc!, Messageid:Messageid)
//check with id's from core data
if (readRecordCoreData(result["MessageID"])==false)
{
Notification.append(newMessages)
}
}
}
return Notification
}
//check id
func readRecordCoreData(Jsonid: String) -> Bool {
var idStaus = false
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let fetchRequest = NSFetchRequest(entityName: "ItemLog")
//3
do {
let resultsCD = try! managedContext.executeFetchRequest(fetchRequest)
if (resultsCD.count > 0) {
for i in 0 ..< resultsCD.count {
let match = resultsCD[i] as! NSManagedObject
let id = match.valueForKey("notificationID") as! String
if (Jsonid as String! == id)
{
idStaus = true
}
else{
idStaus = false
}
}
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
return idStaus
}
One of your methods is static and the other one is not :
func readRecordCoreData(Jsonid: String) -> Bool
static func MessagesWithJSON(results: NSArray) -> [Notifications]
Depending on what you want to accomplish you could declare both static, none, or replace
//check with id's from core data
if (readRecordCoreData(result["MessageID"])==false)
{
Notification.append(newMessages)
}
By
//check with id's from core data
if (Notifications.readRecordCoreData(Messageid)==false)
{
Notification.append(newMessages)
}
Not sure if the code will work past compilation however as there are many readability issues

Swift: Unable to get array values from singleton class

Hi I retrived value from JSON and stored in NSMutableArray. I have tried this like Singleton. I have used empty swift file for this. Datas successfully retrieved and stored in NSMutableArray which is already declared in mainViewController. Then, if I use that NSMutableArray value in mainViewController, it shows empty array.
My coding is below. Kindly guide me.
Empty Swift File
public class json_file{
var prod_Obj = product_mainVC()
class var shared: json_file
{
struct Static
{
static let instance: json_file = json_file()
}
return Static.instance
}
func dataFromJSON()
{
let url = NSURL(string: "http://........--...4900a20659")!
var data : NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMapped, error: nil)!
var dict: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
let dataArray = dict["data"] as [[String:AnyObject]] // The array of dictionaries
for object in dataArray {
let category_name = object["category_name"] as String
prod_Obj.ct_name_arr.addObject(category_name)
let category_child = object["category_child"] as [[String:AnyObject]]
for child in category_child {
let sub_category_name = child["sub_category_name"] as String
prod_Obj.sub_ct_name_arr.addObject(sub_category_name)
}
}
println(prod_Obj.ct_name_arr) //Here value is Getting
println(prod_Obj.sub_ct_name_arr) //Here value is Getting
}
}
viewDidLoad
{
json_file.shared.dataFromJSON()
println(ct_name_arr) //Prints Empty Array [Intially Declared as NSMutableArray]
println(sub_ct_name_arr) //Prints Empty Array [Intially Declared as NSMutableArray]
}
I was trying understand the problem, but I can't see the product_mainVC. Because this I remake your class with little modifications.
class JsonFile
{
private(set) var categoryNames:[String];
private(set) var subCategoryNames:[String];
class let shared:JsonFile = JsonFile();
private init()
{
self.categoryNames = [];
self.subCategoryNames = [];
}
func dataFromJson()
{
let url = NSURL(string: "http://........--...4900a20659")!
if let data : NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMapped, error: nil)
{
if let dict: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary
{
if let dataArray = dict["data"] as? [[String:AnyObject]] // The array of dictionaries
{
for object in dataArray {
let category_id = object["category_id"] as Int
let category_name = object["category_name"] as String
categoryNames.append(category_name);
let category_child = object["category_child"] as [[String:AnyObject]]
for child in category_child {
let sub_category_id = child["sub_category_id"] as Int
let sub_category_name = child["sub_category_name"] as String
subCategoryNames.append(sub_category_name);
}
}
}
}
}
println(categoryNames);
println(subCategoryNames);
}
}
I did
Modify your way to do Singleton to a safe and more simple mode, create the arrays categoryNames and subCategoryNames internal in class because this is better to manipulate, and protect your fetch data to safe from possibles crash.
Implementation
JsonFile.shared.dataFromJson();
println("count categoryNames");
println(JsonFile.shared.categoryNames.count);
println("count subCategoryNames");
println(JsonFile.shared.subCategoryNames.count);
You need think about
This code is sync, and because this if you have a big data or request slow, the main thread from your application will freeze waiting return and it is bad for your user. Think if is necessary be sync.
let category_id = object["category_id"] as Int is never used. Why do you stay with this in code?