I'm making an app that parses JSON data & populates a tableview. In this app i want to make a SearchBar to search the id's. Everything is fine with parsing and populating the tableview but I am having problem with the searching. When I run the app I am gettin the following error: terminating with uncaught exception of type NSException
I have two arrays, first one is the main one and the other one is filtered one.
Requirement: I want to search array by "DesenNo" which i declared in my model.
Here are my codes:
ViewController:
import UIKit
import Foundation
import os.log
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating, HomeModelProtocol {
//Properties
var feedItems: NSArray = NSArray()
var detailViewController: detailsVC? = nil
var searchActive : Bool = false
var filteredData:[String] = []
var resultSearchController:UISearchController!
#IBOutlet weak var listTableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
resultSearchController = UISearchController(searchResultsController: nil)
resultSearchController.searchResultsUpdater = self
resultSearchController.hidesNavigationBarDuringPresentation = false
resultSearchController.dimsBackgroundDuringPresentation = false
resultSearchController.searchBar.searchBarStyle = UISearchBarStyle.prominent
resultSearchController.searchBar.sizeToFit()
self.listTableView.tableHeaderView = resultSearchController.searchBar
self.listTableView.dataSource = self
let homeModel = HomeModel()
homeModel.delegate = self
homeModel.downloadItems()
}
func itemsDownloaded(items: NSArray) {
feedItems = items
self.listTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if resultSearchController.isActive {
return filteredData.count
}
else {
return feedItems.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Retrieve cell
let cellIdentifier: String = "BasicCell"
let myCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MyTableCell
// Get the location to be shown
// Get references to labels of cell
//Label1
if resultSearchController.isActive {
let item: LocationModel = feedItems[indexPath.row] as! LocationModel
let desenNoToString = item.DesenNo
let desenString = "\(desenNoToString)"
let regex = try! NSRegularExpression(pattern:"\"(.*)\"")
if let match = regex.firstMatch(
in: desenString, range:NSMakeRange(0,desenString.utf16.count)) {
let result = (desenString as NSString).substring(with: match.range(at:1))
myCell.label1!.text = result
}
//Label2
let dolarToString = item.Dolar
let dolarString = "\(dolarToString)"
if let match = regex.firstMatch(
in: dolarString, range:NSMakeRange(0,dolarString.utf16.count)) {
let result = (dolarString as NSString).substring(with: match.range(at:1))
myCell.label2!.text = result
}
//Label3
let zeminToString = item.Zemin
let zeminString = "\(zeminToString)"
if let match = regex.firstMatch(
in: zeminString, range:NSMakeRange(0,zeminString.utf16.count)) {
let result = (zeminString as NSString).substring(with: match.range(at:1))
myCell.label3!.text = result
}
//Label4
let renkToString = item.Renk
let renkString = "\(renkToString)"
if let match = regex.firstMatch(
in: renkString, range:NSMakeRange(0,renkString.utf16.count)) {
let result = (renkString as NSString).substring(with: match.range(at:1))
myCell.label4!.text = result
}
//Label5
let enToString = item.En
let enString = "\(enToString)"
if let match = regex.firstMatch(
in: enString, range:NSMakeRange(0,enString.utf16.count)) {
let result = (enString as NSString).substring(with: match.range(at:1))
myCell.label5!.text = result
}
//Label6
let euroToString = item.Euro
let euroString = "\(euroToString)"
if let match = regex.firstMatch(
in: euroString, range:NSMakeRange(0,euroString.utf16.count)) {
let result = (euroString as NSString).substring(with: match.range(at:1))
myCell.label6!.text = result
}
}else {
let item: LocationModel = feedItems[indexPath.row] as! LocationModel
let desenNoToString = item.DesenNo
let desenString = "\(desenNoToString)"
let regex = try! NSRegularExpression(pattern:"\"(.*)\"")
if let match = regex.firstMatch(
in: desenString, range:NSMakeRange(0,desenString.utf16.count)) {
let result = (desenString as NSString).substring(with: match.range(at:1))
myCell.label1!.text = result
}
//Label2
let dolarToString = item.Dolar
let dolarString = "\(dolarToString)"
if let match = regex.firstMatch(
in: dolarString, range:NSMakeRange(0,dolarString.utf16.count)) {
let result = (dolarString as NSString).substring(with: match.range(at:1))
myCell.label2!.text = result
}
//Label3
let zeminToString = item.Zemin
let zeminString = "\(zeminToString)"
if let match = regex.firstMatch(
in: zeminString, range:NSMakeRange(0,zeminString.utf16.count)) {
let result = (zeminString as NSString).substring(with: match.range(at:1))
myCell.label3!.text = result
}
//Label4
let renkToString = item.Renk
let renkString = "\(renkToString)"
if let match = regex.firstMatch(
in: renkString, range:NSMakeRange(0,renkString.utf16.count)) {
let result = (renkString as NSString).substring(with: match.range(at:1))
myCell.label4!.text = result
}
//Label5
let enToString = item.En
let enString = "\(enToString)"
if let match = regex.firstMatch(
in: enString, range:NSMakeRange(0,enString.utf16.count)) {
let result = (enString as NSString).substring(with: match.range(at:1))
myCell.label5!.text = result
}
//Label6
let euroToString = item.Euro
let euroString = "\(euroToString)"
if let match = regex.firstMatch(
in: euroString, range:NSMakeRange(0,euroString.utf16.count)) {
let result = (euroString as NSString).substring(with: match.range(at:1))
myCell.label6!.text = result
}
}
return myCell
}
func updateSearchResults(for searchController: UISearchController) {
if searchController.isActive {
filteredData.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (feedItems as NSArray).filtered(using: searchPredicate)
filteredData = array as! [String]
listTableView.reloadData()
}
else {
filteredData.removeAll(keepingCapacity: false)
filteredData = feedItems as! [String]
listTableView.reloadData()
}
}
}
LocationModel.Swift
import UIKit
class LocationModel: NSObject {
//properties
var DesenNo: String?
var Dolar: String?
var Zemin: String?
var En: String?
var Euro: String?
var Renk: String?
//empty constructor
override init()
{
}
//construct with #name, #address, #latitude, and #longitude parameters
init(DesenNo: String, Dolar: String, Zemin: String, En: String, Euro: String, Renk: String) {
self.DesenNo = DesenNo
self.Dolar = Dolar
self.Zemin = Zemin
self.En = En
self.Euro = Euro
self.Renk = Renk
}
//prints object's current state
override var description: String {
return "Desen: \(DesenNo), Dolar: \(Dolar), Zemin: \(Zemin), Renk: \(Renk), En: \(En), Euro: \(Euro) "
}
}
HomeModel.Swift
import UIKit
protocol HomeModelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject {
//properties
weak var delegate: HomeModelProtocol!
let urlPath = "http://aktul.com/den.php" //this will be changed to the path where service.php lives
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let urunler = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let urun = LocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let desen = jsonElement["DesenNo"] as? String,
let dolar = jsonElement["Dolar"] as? String,
let zemin = jsonElement["Zemin"] as? String,
let renk = jsonElement["Renk"] as? String,
let en = jsonElement["En"] as? String,
let euro = jsonElement["Euro"] as? String
//let longitude = jsonElement["Longitude"] as? String
{
urun.DesenNo = desen
urun.Dolar = dolar
urun.Zemin = zemin
urun.Renk = renk
urun.En = en
urun.Euro = euro
}
urunler.add(urun)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: urunler)
})
}
}
Update with following code in updatesearchResults function
func updateSearchResults(for searchController: UISearchController) {
if searchController.isActive {
filteredData.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = self.feedItems.filter { searchPredicate.evaluate(with: ($0 as! LocationModel).DesenNo) }
let filterArray = array.map {($0 as! LocationModel).DesenNo}
filteredData = filterArray as! [String]
tabelView.reloadData()
}
else {
filteredData.removeAll(keepingCapacity: false)
tabelView.reloadData()
}
}
Related
I have run into a problem where I can save and load into and from CoreData in Swift for my iOS app, but I run into a problem where I have tried to guard for duplicate entries, but it does not seem to work. can anyone tell me where I went wrong? Thanks!
My ViewController class:
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource {
#IBOutlet weak var headerLabel:UILabel!
#IBOutlet weak var myTableView: UITableView!
var lenders = [LenderData]()
var lendersTemp = [LenderData]()
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.rowHeight = 90
myTableView.delegate = self
myTableView.dataSource = self
let fetchRequest: NSFetchRequest<LenderData> = LenderData.fetchRequest()
do {
let lenders = try PersistenceService.context.fetch(fetchRequest)
self.lenders = lenders
} catch {
// Who cares....
}
downloadJSON {
for tempLender in self.lendersTemp {
if !self.lenders.contains(where: {$0.id == tempLender.id}) {
self.lenders.append(tempLender)
}
}
self.lendersTemp.removeAll()
PersistenceService.saveContext()
self.myTableView.reloadData()
}
}
func downloadJSON(completed: #escaping () -> ()) {
let url = URL(string: "https://api.kivaws.org/v1/loans/newest.json")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print("JSON not downloaded")
} else {
if let content = data {
do {
let myJSONData = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
var imageID:Int64 = -1
var country:String = "N/A"
var latLongPair:String = "0.000000 0.000000"
var town:String = "N/A"
if let loans = myJSONData["loans"] as? NSArray {
for i in 0...loans.count-1 {
if let lender = loans[i] as? NSDictionary {
if let imageData = lender["image"] as? NSDictionary { imageID = imageData["id"] as! Int64 }
if let countryData = lender["location"] as? NSDictionary {
country = countryData["country"] as! String
town = countryData["town"] as! String
if let geo = countryData["geo"] as? NSDictionary {
latLongPair = geo["pairs"] as! String
}
}
let newLender = LenderData(context: PersistenceService.context)
newLender.id = lender["id"] as! Int64
newLender.name = lender["name"] as? String
newLender.image_id = imageID
newLender.activity = lender["activity"] as? String
newLender.use = lender["use"] as? String
newLender.loan_amount = lender["loan_amount"] as! Int32
newLender.funded_amount = lender["funded_amount"] as! Int32
newLender.country = country
newLender.town = town
newLender.geo_pairs = latLongPair
self.lendersTemp.append(newLender)
}
}
}
DispatchQueue.main.async {
completed()
}
} catch {
print("Error occured \(error)")
}
}
}
}
task.resume()
}
}
EDIT
Added the part of the code where I populate the lendersTemp array
I quote matt on this one from the comments:
So... You are appending to self.lendersTemp on a background thread but reading it on the main thread. Instead, get rid of it and just pass the data right thru the completed function.
Which is exactly what I did. And this worked
I am working on a project to shows news feeds to the user.
I am calling a function getNewsFeeds() to get news feeds.
I will generate new newsfeeds every one hour
ViewDidLoad(){
get current time in "HH" format and store it in currentTime
Store this currentTime in to a HoursVar variable using UserDefaults
}
ViewDidAppear(){
if( currentTime - HoursVar >= 1){
getNewsFeeds
}else{
}
retreiveStoredValuesFromUserDeafults()
}
I dont know where exactly to setup my tableViewDataSOurce and Delegate methods and reloadData to populate the tableView when getting data from the saved Userdefaults retreiveStoredValuesFromUserDeafults()
override func viewDidLoad() {
super.viewDidLoad()
hoursFormatter.dateFormat = "HH"
hoursVar = Int(hoursFormatter.string(from: hours))!
if hoursVar > 12 {
hoursVar = hoursVar - 12
}
self.defaults.set(self.hoursVar, forKey: "hoursVar")
customNavBar()
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
feedsArray = ["Reliance","Economy"]
}
override func viewDidAppear(_ animated: Bool) {
//getRssFeeds()
if((hoursVar - myHoursVar) == 1 && (hoursVar - myHoursVar) > 1){
getRssFeeds()
}else{
feedsTable.register(UITableViewCell.self, forCellReuseIdentifier: "newsFeeds")
self.feedsTable.delegate = self
self.feedsTable.dataSource = self
retreiveMyArrayData()
feedsTableView.reloadData()
}
}
func getRssFeeds(){
for i in 0..<feedsArray.count{
let url = URL(string: "https://api.cognitive.microsoft.com/bing/v5.0/news/search?q=\(feedsArray[i])&count=3&mkt=en-in")
var request = URLRequest(url: url!)
request.setValue("My Subscription Key", forHTTPHeaderField: "Ocp-Apim-Subscription-Key")
Alamofire.request(request as URLRequest).responseJSON{response in
if let json = response.result.value as? [String:AnyObject]{
if let value = json["value"]{
//
print("json \(json)")
for j in 0..<value.count{
let items = value[j] as! [String:AnyObject]
let name = items["name"] as! String
let url = items["url"] as! String
let description = items["description"] as! String
let datePublished = items["datePublished"] as! String
let dateAndTime = datePublished.replacingOccurrences(of: "T", with: " ")
self.feedsName.append(name)
self.feedsUrl.append(url)
self.feedsDescription.append(description)
self.feedsDatePublished.append(dateAndTime)
if let image = items["image"] as? [String:AnyObject]{
if let thumbnail = image["thumbnail"] as? [String:AnyObject]{
let contentUrl = thumbnail["contentUrl"] as! String
self.feedsContentUrl.append(contentUrl)
}
}else{
self.feedsContentUrl.append(self.errorImage)
}
if let provider = items["provider"]{
for i in 0..<provider.count{
let items = provider[i] as! [String:AnyObject]
let providerName = items["name"] as! String
self.feedsProvider.append(providerName)
}
}
self.feedsTable.delegate = self
self.feedsTable.dataSource = self
self.feedsTable.reloadData()
self.defaults.set(self.feedsUrl, forKey: "feedsUrl")
self.defaults.set(self.feedsDescription, forKey: "feedsDescription")
self.defaults.set(self.feedsName, forKey: "feedsName")
self.defaults.set(self.feedsProvider, forKey: "feedsProvider")
self.defaults.set(self.feedsContentUrl, forKey: "feedsContentUrl")
self.defaults.set(self.feedsDatePublished, forKey: "feedsDatePublished")
print("All Counts \(self.feedsName.count)")
}
}
}
}
}
}
func slideOpen(){
self.revealViewController().revealToggle(animated: true)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feedsName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "newsFeeds") as! newsFeeds
randomNumberArray = randomNumber()
//self.feedsRandomArray.append(self.feedsRandom)
print("feedsRandom \(feedsRandom)")
selectedRow = randomNumberArray[indexPath.row]
let url = URL(string: feedsContentUrl[randomNumberArray[indexPath.row]])
do{
let data = try Data(contentsOf: url!)
cell.feedsImage.image = UIImage(data: data )
}catch{
print(error)
}
let tap = UITapGestureRecognizer(target: self, action: #selector(HomeViewController.tapFunction))
let titleAttributes = [NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline), NSForegroundColorAttributeName: UIColor.purple]
let titleString = NSAttributedString(string: feedsName[randomNumberArray[indexPath.row]] , attributes: titleAttributes)
cell.feedsHeadlines.isUserInteractionEnabled = true
cell.feedsHeadlines.addGestureRecognizer(tap)
cell.feedsHeadlines.attributedText = titleString
cell.feedsDescription.text = feedsDescription[randomNumberArray[indexPath.row]]
cell.feedsPublisherName.text = feedsProvider[randomNumberArray[indexPath.row]]
cell.publishedOn.text = feedsDatePublished[randomNumberArray[indexPath.row]]
//print("All Counts \(myFeedsName.count) \(myFeedsProvider.count) \(myFeedsContentUrl.count) \(myFeedsUrl.count) \(myFeedsDescription.count) \(myFeedsDescription.count)")
return cell
}
func tapFunction(sender:UITapGestureRecognizer) {
let safariVC = SFSafariViewController(url: NSURL(string: feedsUrl[selectedRow]) as! URL)
self.present(safariVC, animated: true, completion: nil)
safariVC.delegate = self
}
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true, completion: nil)
}
func randomNumber() -> [Int] {
let feedsIndex = feedsName.count - 1
var randomNumber = Int(arc4random_uniform(UInt32(feedsIndex)))
print("Randome number \(randomNumber) \(randomNumberArray)")
for k in 0..<randomNumberArray.count{
while randomNumber == randomNumberArray[k] {
randomNumber = Int(arc4random_uniform(UInt32(feedsIndex)))
}
}
randomNumberArray.append(randomNumber)
self.defaults.set(self.randomNumberArray, forKey: "randomNumberArray")
return randomNumberArray
}
func retreiveMyArrayData(){
myFeedsUrl = defaults.stringArray(forKey: "feedsUrl") ?? [String]()
myFeedsDescription = defaults.stringArray(forKey: "feedsDescription") ?? [String]()
myFeedsName = defaults.stringArray(forKey: "feedsName") ?? [String]()
myFeedsProvider = defaults.stringArray(forKey: "feedsProvider") ?? [String]()
myFeedsContentUrl = defaults.stringArray(forKey: "feedsContentUrl") ?? [String]()
myFeedsDatePublished = defaults.stringArray(forKey: "feedsDatePublished") ?? [String]()
myHoursVar = defaults.integer(forKey: "hoursVar")
myFeedsRandom = defaults.array(forKey: "randomNumberArray") as! [Int]
print("Values \(myHoursVar) \(myFeedsProvider) \(myFeedsUrl.count)")
}
You can set UITableViewDataSourceand UITableViewDelegate into .xib
//Setting datasource & delegate for tableview inside viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.feedsTableView.delegate = self
self.feedsTableView.datasource = self
}
Now, you need to reload the tableview when you setValue & retrieve the value to the userDefaults. self.feedsTableView.reloadData()
If this didn't helped you, please let me know. I'll work more to provide you with a complete workflow for the above project.
I'm creating a simple app that shows the details of every character fo Star Wars using SWAPI. Now i'm trying to get the species but Xcode is telling me that found a nil while unwrapping an optional value when is trying to print _species. Here's the code:
func DownlaodCompleted(complete: DownloadComplete) {
let url = NSURL(string: _urlperson)!
Alamofire.request(.GET, url).responseJSON { (response: Response<AnyObject, NSError>) -> Void in
let result = response.result
if let dict = result.value as? Dictionary<String, AnyObject> {
if let height = dict["height"] as? String {
self._height = height
}
if let gender = dict["gender"] as? String {
self._gender = gender
}
if let birthYear = dict["birth_year"] as? String {
self._birthYear = birthYear
}
if let species = dict["species"] as? [Dictionary<String, String>] {
let urlSpecies = NSURL(string: self._urlSpecies)!
Alamofire.request(.GET, urlSpecies).responseJSON(completionHandler: { (response2: Response<AnyObject, NSError>) -> Void in
let result = response2.result
if let speciesDict = result.value as? Dictionary<String, AnyObject> {
if let name = speciesDict["name"] as? String {
self._species = name
}
}
})
}
print(self._species)
print(self._height)
}
}
}
and here the class of Constants:
let URL_BASE = "http://swapi.co"
let URL_PEOPLE = "/api/people/"
let URL_SPECIES = "/api/species/1/"
typealias DownloadComplete = () -> ()
Here's sample code that I used after creating an empty "Single View Project", and adding the 2 "pods" Alamofire, and SwiftyJSON to the project.
The sample code has one of your URLs and a commented out URL to another site.
import UIKit
import Alamofire
import SwiftyJSON // No such module "SwiftyJSON"
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var arrResults = [[String:AnyObject]]() //Array of dictionary
override func viewDidLoad() {
super.viewDidLoad()
self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
self.tableView = UITableView(frame:self.view!.frame)
self.tableView!.delegate = self
self.tableView!.dataSource = self
self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "jsonCell")
self.view?.addSubview(self.tableView)
Alamofire.request(.GET, "http://swapi.co/api/people/?format=json").responseJSON { (responseData) -> Void in
let swiftyJsonVar = JSON(responseData.result.value!)
for element in swiftyJsonVar["results"].arrayValue {
let name = element["name"].string!
let homeworld = element["homeworld"].string!
let object : Dictionary<String, String> = ["name": name, "homeworld": homeworld]
self.arrResults.append(object)
}
if self.arrResults.count > 0 {
self.tableView.reloadData()
}
}
// Alamofire.request(.GET, "http://api.androidhive.info/contacts/").responseJSON { (responseData) -> Void in
// let swiftyJsonVar = JSON(responseData.result.value!)
//
// if let resData = swiftyJsonVar["contacts"].arrayObject {
// self.arrResults = resData as! [[String:AnyObject]]
// }
// if self.arrResults.count > 0 {
// self.tableView.reloadData()
// }
// }
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "jsonCell")
var dict = arrResults[indexPath.row]
// Use these lines with: "http://swapi.co/api/people/?format=json"
cell.textLabel?.text = dict["name"] as? String
cell.detailTextLabel?.text = dict["homeworld"] as? String
// Use these lines with: "http://api.androidhive.info/contacts/"
// cell.textLabel?.text = dict["name"] as? String
// cell.detailTextLabel?.text = dict["email"] as? String
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrResults.count
}
}
I have got the response data in the log window but I am not able to populate on the tableView dynamically. I have tried many methods but not working
// send request to URL
let urlPath:String = "http://api.androidhive.info/contacts/"
var url:NSURL = NSURL(string: urlPath)!
var request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request1.HTTPMethod = "POST"
var stringPost = "msg=123" ///key and value
let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
request1.timeoutInterval = 60
request1.HTTPBody = data
request1.HTTPShouldHandleCookies = false
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler: {(response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
//print object response
println("response = \(response)")
//print response body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("response data = \(responseString)")
The data is coming from the url. I can see it.
// Extract JSON
var err: NSError?
let json : NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &err) as! NSDictionary
if let items = json["contacts"] as? [[String:AnyObject]]
{
for item in items {
// construct your model objects here
self.contactList.append(Person(dictionary:item))
}
// dispatch_async(dispatch_get_main_queue()) {
// self.tableView.reloadData()
}
The above code line is not appending data (not working).
Table view code
//how many sections
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//how many rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contactList.count
//return cellCount
}
//contents
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// var cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
// cell.textLabel?.text = "aaa"
let person = contactList[indexPath.row]
cell.textLabel?.text = person.name
return cell
}
Please tell me where the problem is.
That's a good example to create a custom class
class Person { // can be also a struct
let id : String
let name : String
let email : String
let address : String
let gender : String
let phone : String
init(dictionary : [String : AnyObject]) {
id = dictionary["id"] as? String ?? ""
name = dictionary["name"] as? String ?? ""
email = dictionary["email"] as? String ?? ""
address = dictionary["address"] as? String ?? ""
gender = dictionary["gender"] as? String ?? ""
phone = dictionary["id"] as? String ?? ""
}
}
Then create contactList as
var contactList = [Person]()
and populate the list with
if let items = json["contacts"] as? [[String:AnyObject]]
{
for item in items {
// construct your model objects here
self.contactList.append(Person(dictionary:item))
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
and display the name in each cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// var cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
let person = contactList[indexPath.row]
cell.textLabel?.text = person.name
return cell
}
If all values of the dictionary containing the person data are of type String you can change the following lines to be still more specific
in Person
init(dictionary : [String : String]) {
id = dictionary["id"] ?? ""
...
phone = dictionary["id"] ?? ""
}
in the view controller
if let items = json["contacts"] as? [[String:String]]
Create NSObject class
public class Global: NSObject
{
let name : String!
.
.
}
Within for item in items
var object: ObjectClass = ObjectClass()
object.id = item["id"]!
.
.
self.contactList.append(object)
In cellForRowAtIndexPath
var object: ObjectClass = self.contactList [indexPath.row] as! ObjectClass;
///get the values as
cell.label.text = object.name;
Instead create model. you can create Class for Contact.
class Contact {
var id : String?
var name : String?
}
Create a Sample responses.
// Contact1
let cont1 : NSMutableDictionary = NSMutableDictionary.init(object: "7", forKey: "id");
cont1.setValue("vignesh", forKey: "name");
// Contact2
let cont2 : NSMutableDictionary = NSMutableDictionary.init(object: "8", forKey: "id");
cont2.setValue("karthi", forKey: "name");
let contactArray :NSArray = NSArray.init(array: [cont1,cont2]);
// Response Dictionary
let responseDic : NSMutableDictionary = NSMutableDictionary.init(object: contactArray, forKey: "contacts");
Parse Response value.
// Create Contact list Array.
var contactList : Array<Contact> = []
if let items = responseDic["contacts"] as? NSArray
{
for item in items {
// construct your model objects here
let id: NSString = item["id"] as! NSString
let name: NSString = item["name"] as! NSString
let contUser : Contact = Contact.init();
contUser.id = id as String;
contUser.name = name as String;
contactList.append(contUser)
}
}
List item
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate {
#IBOutlet weak var tableViewCountry: UITableView!
var names: [String] = []
var contacts: [String] = []
var gender: [String] = []
var mob:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
tableViewCountry.dataSource = self
tableViewCountry.delegate = self
self.tableViewCountry.register(UINib(nibName: "ContactTableViewCell", bundle: nil), forCellReuseIdentifier: "ContactTableViewCell")
let url=URL(string:"http://api.androidhive.info/contacts/")
do {
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["contacts"] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
names.append(aObject["name"] as! String)
contacts.append(aObject["email"] as! String)
gender.append(aObject["gender"] as! String)
let phone = aObject["phone"]
mob.append(phone?["mobile"] as! String)
}
}
print(allContacts)
print(names)
print(contacts)
self.tableViewCountry.reloadData()
}
catch {
print("error")
}
}
I want to add a search bar in my tableview which is populated with data from Core Data. Below is parts of code from my TableViewController. How do I begin implementing the searchbar function after placing one on the tableview?
let managedObjectContext =
(UIApplication.sharedApplication().delegate
as! AppDelegate).managedObjectContext
var fetchedLastName = [String]()
var fetchedFirstName = [String]()
var fetchedImage = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reloadData:",name:"load", object: nil)
let entityDescription =
NSEntityDescription.entityForName("Faculty",
inManagedObjectContext: managedObjectContext)
let request = NSFetchRequest()
request.entity = entityDescription
do{
let objects = try managedObjectContext.executeFetchRequest(request)
let results = objects
if results.count > 0 {
for var i = 0; i < results.count; i += 1{
let match = results[i] as! NSManagedObject
fetchedLastName.append((match.valueForKey("lastname") as? String)!)
fetchedFirstName.append((match.valueForKey("firstname") as? String)!)
let image = match.valueForKey("image") as! NSData
fetchedImage.append(UIImage(data: image)!)
}
} else {
}
}
catch{}
}
func reloadData(notification: NSNotification){
fetchedLastName.removeAll()
fetchedFirstName.removeAll()
fetchedImage.removeAll()
let entityDescription =
NSEntityDescription.entityForName("Faculty",
inManagedObjectContext: managedObjectContext)
let request = NSFetchRequest()
request.entity = entityDescription
do{
let objects = try managedObjectContext.executeFetchRequest(request)
let results = objects
if results.count > 0 {
for var i = 0; i < results.count; i += 1{
let match = results[i] as! NSManagedObject
fetchedLastName.append((match.valueForKey("lastname") as? String)!)
fetchedFirstName.append((match.valueForKey("firstname") as? String)!)
let image = match.valueForKey("image") as! NSData
fetchedImage.append(UIImage(data: image)!)
}
} else {
}
}
catch{}
self.tableView.reloadData()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TEACH", forIndexPath: indexPath) as! TEACHTableViewCell
let row = indexPath.row
print(fetchedFirstName)
cell.facultyName.text = fetchedLastName[row] + ", " + fetchedFirstName[row]
cell.facultyImage.image = fetchedImage[row]
return cell
}
}
Try this code all tested:
//
// TEACHTableViewController.swift
// TEACH
//
// Created by ICST340.N1 on 9/29/15.
// Copyright © 2015 IyoTugs. All rights reserved.
//
import UIKit
import CoreData
class TEACHTableViewController: UITableViewController, UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating {
var searchController = UISearchController()
var filteredTableData = [[String: AnyObject?]]()
var tableData = [[String: AnyObject?]]()
let managedObjectContext =
(UIApplication.sharedApplication().delegate
as! AppDelegate).managedObjectContext
var fetchedLastName = [String]()
var fetchedFirstName = [String]()
var fetchedImage = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
//setup search controller
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.delegate = self
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
searchController.searchBar.sizeToFit()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reloadData:",name:"load", object: nil)
let entityDescription =
NSEntityDescription.entityForName("Faculty",
inManagedObjectContext: managedObjectContext)
let request = NSFetchRequest()
request.entity = entityDescription
do{
let objects = try managedObjectContext.executeFetchRequest(request)
let results = objects
if results.count > 0 {
for var i = 0; i < results.count; i += 1{
let match = results[i] as! NSManagedObject
fetchedLastName.append((match.valueForKey("lastname") as? String)!)
fetchedFirstName.append((match.valueForKey("firstname") as? String)!)
//added this is convert the image
let image = match.valueForKey("image") as! NSData
let realImage = UIImage(data: image)!
fetchedImage.append(UIImage(data: image)!)
tableData.append(["firstName" : match.valueForKey("firstname"), "lastName" : match.valueForKey("firstname"), "image" : realImage])
}
} else {
}
}
catch{}
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
func reloadData(notification: NSNotification){
fetchedLastName.removeAll()
fetchedFirstName.removeAll()
//Added this to remove all images
fetchedImage.removeAll()
tableData.removeAll()
let entityDescription =
NSEntityDescription.entityForName("Faculty",
inManagedObjectContext: managedObjectContext)
let request = NSFetchRequest()
request.entity = entityDescription
do{
let objects = try managedObjectContext.executeFetchRequest(request)
let results = objects
if results.count > 0 {
for var i = 0; i < results.count; i += 1{
let match = results[i] as! NSManagedObject
fetchedLastName.append((match.valueForKey("lastname") as? String)!)
fetchedFirstName.append((match.valueForKey("firstname") as? String)!)
//added this is convert the image
let image = match.valueForKey("image") as! NSData
let realImage = UIImage(data: image)!
fetchedImage.append(UIImage(data: image)!)
tableData.append(["firstName" : match.valueForKey("firstname"), "lastName" : match.valueForKey("firstname"), "image" : realImage])
}
} else {
}
}
catch{}
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(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 searchController.active {
return filteredTableData.count
} else {
return fetchedLastName.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TEACH", forIndexPath: indexPath) as! TEACHTableViewCell
if searchController.active {
let row = indexPath.row
print(fetchedFirstName)
let firstName = filteredTableData[row]["firstName"] as! String
let lastName = filteredTableData[row]["lastName"] as! String
let image = filteredTableData[row]["image"] as! UIImage
cell.facultyName.text = lastName + ", " + firstName
cell.facultyImage.image = image
} else {
let row = indexPath.row
print(fetchedFirstName)
cell.facultyName.text = fetchedLastName[row] + ", " + fetchedFirstName[row]
cell.facultyImage.image = fetchedImage[row]
}
return cell
}
func filterContentForSearchText(searchText: String) {
for singleTableData in tableData {
let firstname = singleTableData["firstName"] as! String
let lastname = singleTableData["lastName"] as! String
let image = singleTableData["image"] as! UIImage
print(firstname)
print(lastname)
if searchText != "" {
if (firstname.rangeOfString(searchText) != nil) {
filteredTableData.append(["firstName" : firstname, "lastName" : lastname, "image" : image])
} else if (lastname.rangeOfString(searchText) != nil) {
filteredTableData.append(["firstName" : firstname, "lastName" : lastname, "image" : image])
}
} else {
filteredTableData.append(["firstName" : firstname, "lastName" : lastname, "image" : image])
}
}
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
filteredTableData.removeAll()
filterContentForSearchText(searchController.searchBar.text!)
tableView.reloadData()
}
}