I am fetching data from an API and works fine when i type in a city in console. The problem i am facing now is with UISearchController and tableView in the code below i want to populate my searched city in the tableView. Now it does not show up anything when i run the app, except in my console that logs my request when a searched in the searchbar
LOG:
Search text: London
Creating request..
Task started
City name: London
Success! JSON decoded
this means using the searchfunction with the APIrequest works, except that i cant see it in my tableView
here is my viewController
import UIKit
class ViewController: UIViewController{
#IBOutlet weak var tblView: UITableView!
let mWeather = WeatherAPI()
var weatherArray = [WeatherStruct]()
var filteredWeatherArray : [String] = []
// dummy data
let originalArray = ["gothenburg", "london", "stockholm", "new york", "washington DC", "thailand", "china", "spain", "paris"]
var searching: Bool {
if weatherArray.count > 0 {
return true
} else {
return false
}
}
let searchController: UISearchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "type in your city here"
navigationItem.searchController = searchController
tblView.delegate = self
tblView.dataSource = self
}
}
// MARK: - extensions
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text ?? "can not search"
print("Search text: \(searchText)")
mWeather.fetchCurrentWeather(city: searchText) { (WeatherStruct) in}
tblView.reloadData()
}
}
// MARK: - Table view data source
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return weatherArray.count // when something is typed on searchbar
}else{
return filteredWeatherArray.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell", for: indexPath)
if searching {
cell.textLabel?.text = weatherArray[indexPath.row].name
tblView.reloadData()
} else {
cell.textLabel?.text = filteredWeatherArray[indexPath.row]
tblView.reloadData()
}
return cell
}
}
EDIT: as this maybe can help someone to help me = API request handler
func fetchCurrentWeather(city: String, completionHandler: #escaping (WeatherStruct) -> Void) {
// url
let wholeUrl = baseUrlForCurrentWeather + city + appid + metric
let urlString = (wholeUrl)
guard let url: URL = URL(string: urlString) else { return }
// Request
print("Creating request..")
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let unwrappedError = error {
print("Nått gick fel. Error: \(unwrappedError)")
return
}
if let unwrappedData = data {
do {
let decoder = JSONDecoder()
let wdata: WeatherStruct = try decoder.decode(WeatherStruct.self, from: unwrappedData)
print("City name: \(String(describing: wdata.name))")
print("Success! JSON decoded")
completionHandler(wdata)
} catch {
print("Couldnt parse JSON..")
print(error)
}
}
}
// Starta task
task.resume()
print("Task started")
}
You need to update the filteredWeatherArray from the result you are getting from fetchCurrentWeather in your updateSearchResults(for searchController method, here's how:
mWeather.fetchCurrentWeather(city: searchText) { weather in
self.weatherArray = [weather]
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
Edit: Even though the above code might work for you, you might not get the desired result. You are trying to display a list from the array of weatherArray, but when you make a call to fetchCurrentWeather you are getting just one result. I have modified my code to set the one array element to set as the weatherArray and reload.
Related
I'm trying to save data to the core data and then display it on another view controller. I have a table view with custom cell, which have a button. I've created a selector, so when we tap on the button in each of the cell, it should save all the data from the cell. Here is my parent view controller:
import UIKit
import SafariServices
import CoreData
class ViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var pecodeTableView: UITableView!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var savedNews = [SavedNews]()
var newsTitle: String?
var newsAuthor: String?
var urlString: String?
var newsDate: String?
var isSaved: Bool = false
private var articles = [Article]()
private var viewModels = [NewsTableViewCellViewModel]()
private let searchVC = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
pecodeTableView.delegate = self
pecodeTableView.dataSource = self
pecodeTableView.register(UINib(nibName: S.CustomCell.customNewsCell, bundle: nil), forCellReuseIdentifier: S.CustomCell.customCellIdentifier)
fetchAllNews()
createSearchBar()
loadNews()
saveNews()
countNewsToCategory()
}
#IBAction func goToFavouritesNews(_ sender: UIButton) {
performSegue(withIdentifier: S.Segues.goToFav, sender: self)
}
private func fetchAllNews() {
APICaller.shared.getAllStories { [weak self] result in
switch result {
case .success(let articles):
self?.articles = articles
self?.viewModels = articles.compactMap({
NewsTableViewCellViewModel(author: $0.author ?? "Unknown", title: $0.title, subtitle: $0.description ?? "No description", imageURL: URL(string: $0.urlToImage ?? "")
)
})
DispatchQueue.main.async {
self?.pecodeTableView.reloadData()
}
case .failure(let error):
print(error)
}
}
}
private func createSearchBar() {
navigationItem.searchController = searchVC
searchVC.searchBar.delegate = self
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModels.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: S.CustomCell.customCellIdentifier, for: indexPath) as! CustomNewsCell
cell.configure(with: viewModels[indexPath.row])
cell.saveNewsBtn.tag = indexPath.row
cell.saveNewsBtn.addTarget(self, action: #selector(didTapCellButton(sender:)), for: .touchUpInside)
return cell
}
#objc func didTapCellButton(sender: UIButton) {
guard viewModels.indices.contains(sender.tag) else { return }
print("Done")// check element exist in tableview datasource
if !isSaved {
saveNews()
print("success")
}
//Configure selected button or update model
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let article = articles[indexPath.row]
guard let url = URL(string: article.url ?? "") else {
return
}
let vc = SFSafariViewController(url: url)
present(vc, animated: true)
}
//Search
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let text = searchBar.text, !text.isEmpty else {
return
}
APICaller.shared.Search(with: text) { [weak self] result in
switch result {
case .success(let articles):
self?.articles = articles
self?.viewModels = articles.compactMap({
NewsTableViewCellViewModel(author: $0.author ?? "Unknown", title: $0.title, subtitle: $0.description ?? "No description", imageURL: URL(string: $0.urlToImage ?? "")
)
})
DispatchQueue.main.async {
self?.pecodeTableView.reloadData()
self?.searchVC.dismiss(animated: true, completion: nil)
}
case .failure(let error):
print(error)
}
}
}
}
extension ViewController {
func loadNews() {
let request: NSFetchRequest<SavedNews> = SavedNews.fetchRequest()
do {
let savedNews = try context.fetch(request)
//Handle saved news
if savedNews.count > 0 {
isSaved = true
}
} catch {
print("Error fetching data from context \(error)")
}
}
func saveNews() {
//Initialize the context
let news = SavedNews(context: self.context)
//Putting data
news.title = newsTitle
news.author = newsAuthor
news.publishedAt = newsDate
news.url = urlString
do {
try context.save()
} catch {
print("Error when saving data \(error)")
}
}
func countNewsToCategory() {
//Initialize the context
let request: NSFetchRequest<SavedNews> = SavedNews.fetchRequest()
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
])
request.predicate = predicate
do {
savedNews = try context.fetch(request)
} catch {
print("Error fetching data from category \(error)")
}
}
}
I don't know where is the problem, I've created a correct data model, but data could not be saved. Here is my model:
import Foundation
struct APIResponse: Codable {
let articles: [Article]
}
struct Article: Codable {
let author: String?
let source: Source
let title: String
let description: String?
let url: String?
let urlToImage: String?
let publishedAt: String
}
struct Source: Codable {
let name: String
}
And also my model in Core Data:
My second view controller, to which I want display the data:
import UIKit
import CoreData
class FavouriteNewsViewController: UIViewController {
#IBOutlet weak var favTableView: UITableView!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var savedNews = [SavedNews]()
override func viewDidLoad() {
super.viewDidLoad()
favTableView.delegate = self
favTableView.delegate = self
loadSavedNews()
favTableView.register(UINib(nibName: S.FavouriteCell.favouriteCell, bundle: nil), forCellReuseIdentifier: S.FavouriteCell.favouriteCellIdentifier)
// Do any additional setup after loading the view.
}
}
extension FavouriteNewsViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return savedNews.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = favTableView.dequeueReusableCell(withIdentifier: S.FavouriteCell.favouriteCellIdentifier, for: indexPath) as! FavouritesCell
print(savedNews)
let article = savedNews[indexPath.row]
if let articleTitle = article.title {
cell.favTitle.text = articleTitle
}
if let articleAuthor = article.author {
cell.favAuthor.text = articleAuthor
}
if let articleDesc = article.desc {
cell.favDesc.text = article.desc
}
return cell
}
}
extension FavouriteNewsViewController {
func loadSavedNews() {
let request: NSFetchRequest<SavedNews> = SavedNews.fetchRequest()
do {
savedNews = try context.fetch(request)
} catch {
print("Error fetching data from context \(error)")
}
}
func deleteNews(at indexPath: IndexPath) {
// Delete From NSObject
context.delete(savedNews[indexPath.row])
// Delete From current News list
savedNews.remove(at: indexPath.row)
// Save deletion
do {
try context.save()
} catch {
print("Error when saving data \(error)")
}
}
}
you did not assign your properties that you are trying to save
newsTitle,newsAuthor,newsDate,urlString
seems these properties have nil value . make sure these properties have valid value before save .
I created a searchBar programmatically which is connected to a UITableViewController
let locationSearchTable = storyboard!.instantiateViewController(withIdentifier:
"LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController:
locationSearchTable)
resultSearchController.searchResultsUpdater = locationSearchTable
let searchBar = resultSearchController.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Search for places"
navigationItem.titleView = resultSearchController.searchBar
resultSearchController.searchBar.delegate = self
resultSearchController.hidesNavigationBarDuringPresentation = false
resultSearchController.obscuresBackgroundDuringPresentation = true
definesPresentationContext = true
locationSearchTable.mapView = mapView
locationSearchTable.handleMapSearchDelegate = self
It works perfectly. But when i try to assign searchBar to my SearchBars created from storyBoard they don't work. I did delegate connection from storyboard as well.
class MapViewController: UIViewController, UISearchBarDelegate,
UITableViewDelegate {
#IBOutlet weak var myFrom: UISearchBar!
#IBOutlet weak var myTo: UISearchBar!
....
override func viewDidLoad() {
...
myFrom = resultSearchController.searchBar
myTo = resultSearchController.searchBar
myFrom.delegate = self
myTo.delegate = self
I also need tableview results to have same width as searchBar in the pop-up view. Not entire screen width as programmatically created.
I use the subLocality data in the searchBars. For now, I just pull data from MKPlacemarks into searchBars.
I couldn't activate the searchBars.
TableView code:
import Foundation
import UIKit
import MapKit
class LocationSearchTable : UITableViewController {
var handleMapSearchDelegate: HandleMapSearch? = nil
var mapView: MKMapView? = nil
var searchResults = [MKLocalSearchCompletion]()
private var boundingRegion: MKCoordinateRegion = MKCoordinateRegion(MKMapRect.world)
lazy var searchCompleter: MKLocalSearchCompleter = {
let sC = MKLocalSearchCompleter()
sC.delegate = self
sC.resultTypes = .pointOfInterest
sC.region = boundingRegion
return sC
}()
private var places: [MKMapItem]? {
didSet {
tableView.reloadData()
}
}
private var localSearch: MKLocalSearch? {
willSet {
// Clear the results and cancel the currently running local search before starting a new search.
places = nil
localSearch?.cancel()
}
}
/// - Parameter suggestedCompletion: A search completion provided by `MKLocalSearchCompleter` when tapping on a search completion table row
private func search(for suggestedCompletion: MKLocalSearchCompletion) {
let searchRequest = MKLocalSearch.Request(completion: suggestedCompletion)
search(using: searchRequest)
}
/// - Tag: SearchRequest
private func search(using searchRequest: MKLocalSearch.Request) {
// Confine the map search area to an area around the user's current location.
searchRequest.region = boundingRegion
localSearch = MKLocalSearch(request: searchRequest)
localSearch?.start { [unowned self] (response, error) in
guard error == nil else {
self.displaySearchError(error)
return
}
self.places = response?.mapItems
// Used when setting the map's region in `prepareForSegue`.
if let updatedRegion = response?.boundingRegion {
self.boundingRegion = updatedRegion
}
}
}
private func displaySearchError(_ error: Error?) {
if let error = error as NSError?, let errorString = error.userInfo[NSLocalizedDescriptionKey] as? String {
let alertController = UIAlertController(title: "Could not find any places.", message: errorString, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertController, animated: true, completion: nil)
}
}
}
extension LocationSearchTable: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController)
{
searchCompleter.queryFragment = searchController.searchBar.text ?? ""
self.tableView.reloadData()
}
}
extension LocationSearchTable: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
self.tableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// handle error
print("error loading MKLocalSearchCompleter")
}
}
//- Tableview DataSource methods
extension LocationSearchTable {
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let searchResult = searchResults[indexPath.row]
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
cell.textLabel?.text = searchResult.title
cell.detailTextLabel?.text = searchResult.subtitle
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedItem = searchResults[indexPath.row]
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = selectedItem.title
let search = MKLocalSearch(request: request)
search.start { (response, error) in
guard let response = response else {return}
guard let item = response.mapItems.first else {return}
self.handleMapSearchDelegate?.dropPinZoomIn(placemark: item.placemark)
self.dismiss(animated: true, completion: nil)
}
}
}
programmatically created SearchBar
StoryBoard SearchBars
I have spent about three weeks trying to figure this out. I can get the section title to view, but none of the JSON data is showing. When I do a standard "array" contained in the file, it displays.
I have followed every tip and trick out there and I am stuck.
I think this may have something to do with AnyObject and String, but I am missing something. Please see my code below:
import UIKit
import Alamofire
import SwiftyJSON
class UserTableViewCell: UITableViewCell {
#IBOutlet weak var userFirstname: UILabel!
#IBOutlet weak var userLastname: UILabel!
}
class Profile2VC: UITableViewController {
#IBOutlet var userTable: UITableView!
var usertitles = ["First Name", "Last Name", "Email", "Mobile Number"]
var userinfo = [[String:AnyObject]]() //Array of dictionary
override func viewDidLoad() {
super.viewDidLoad()
let defaultValues = UserDefaults.standard
let URL_USER_LOGIN = "https://www.myapp.com/myphp.php"
let userid = "13"
let parameters: Parameters=["id":coolid]
Alamofire.request(URL_USER_LOGIN, method: .get, parameters:
parameters).responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
print(swiftyJsonVar)
if let userData = swiftyJsonVar["user"].arrayObject {
self.userinfo = userData as! [[String:AnyObject]]
//debugPrint(userData)
}
if self.userinfo.count > 0 {
self.userTable.reloadData()
}
}
}
self.userTable.reloadData()
// 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
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return userinfo.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection
section: Int) -> String? {
return "Section \(section)"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell",
for: indexPath) as! UserTableViewCell
//let userTitles = usertitles[indexPath.row]
let userInfo = userinfo[indexPath.row]
cell.userFirstname?.text = userInfo["first_name"] as? String
cell.userLastname?.text = userInfo["last_name"] as? String
//cell.imageView?.image = UIImage(named: fruitName)
//cell.textLabel?.text = usertitles[indexPath.row]
return cell
}
}
First of all you need to reload your table view in main queue. Check below code:
DispatchQueue.main.async {
self.userTable.reloadData()
}
And you are reloading it multiple times which is not good so Remove unwanted reload code and you final code will be:
Alamofire.request(URL_USER_LOGIN, method: .get, parameters: parameters).responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
print(swiftyJsonVar)
if let userData = swiftyJsonVar["user"].arrayObject {
self.userinfo = userData as! [[String:AnyObject]]
//debugPrint(userData)
}
if self.userinfo.count > 0 {
DispatchQueue.main.async {
self.userTable.reloadData()
}
}
}
}
//self.userTable.reloadData() //Remove this code
And once your API call done, Make sure debugPrint(userData) is printing some data and then when you are reloading userTable put a breakpoint in cellForRowAt and confirm that it's calling.
Then if its calling and data is there from server, You are good to go.
But if cellForRowAt method didn't called then you need to check your userTable DataSource and Delegate if it's correctly connected or not.
Try this code :
let API = URL(string:"http://www.myapp.com/myphp.php")
let request = URLRequest(url:API!)
let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
if let data = data {
if String(data: data, encoding: String.Encoding.utf8) != nil {
let data = data
let json = try? JSONSerialization.jsonObject(with: data, options: [])
let jsonData = json as! [[String:Any]]
DispatchQueue.main.sync {
let user = jsonData.flatMap { $0["user"] as? String }
print(user)
self.annocumentTableView.reloadData()
}
}
}
})
task.resume()
i have text Feld and I post text
and I need it to be in deadline
now when I post it will be post not wait to the time then post
I hope you understand me .
SO what I should do?
this was the code I wrote
import Foundation
struct TodoItem {
var title: String
var deadline: Date
var UUID: String
init(deadline: Date, title: String, UUID: String) {
self.deadline = deadline
self.title = title
self.UUID = UUID
}
var isOverdue: Bool {
return (Date().compare(self.deadline) == ComparisonResult.orderedDescending) // deadline is earlier than current date
}
}
2-this is next code i add it all to under stand my vision
so this is to post go next view and more
import Foundation
import UIKit
class TodoList {
class var sharedInstance : TodoList {
struct Static {
static let instance: TodoList = TodoList()
}
return Static.instance
}
fileprivate let ITEMS_KEY = "todoItems"
func allItems() -> [TodoItem] {
let todoDictionary = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) ?? [:]
let items = Array(todoDictionary.values)
return items.map({
let item = $0 as! [String:AnyObject]
return TodoItem(deadline: item["deadline"] as! Date, title: item["title"] as! String, UUID: item["UUID"] as! String!)
}).sorted(by: {(left: TodoItem, right:TodoItem) -> Bool in
(left.deadline.compare(right.deadline) == .orderedAscending)
})
}
func addItem(_ item: TodoItem) {
// persist a representation of this todo item in NSUserDefaults
var todoDictionary = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) ?? Dictionary() // if todoItems hasn't been set in user defaults, initialize todoDictionary to an empty dictionary using nil-coalescing operator (??)
todoDictionary[item.UUID] = ["deadline": item.deadline, "title": item.title, "UUID": item.UUID] // store NSData representation of todo item in dictionary with UUID as key
UserDefaults.standard.set(todoDictionary, forKey: ITEMS_KEY) // save/overwrite todo item list
// create a corresponding local notification
let notification = UILocalNotification()
notification.alertBody = "Todo Item \"\(item.title)\" Is Overdue" // text that will be displayed in the notification
notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view"
notification.fireDate = item.deadline as Date // todo item due date (when notification will be fired)
notification.soundName = UILocalNotificationDefaultSoundName // play default sound
notification.userInfo = ["title": item.title, "UUID": item.UUID] // assign a unique identifier to the notification so that we can retrieve it later
UIApplication.shared.scheduleLocalNotification(notification)
var inputValue = [index]
let request = NSMutableURLRequest(url: URL(string: "http://www.alhumaidi.net/hamsat1.php")!)
request.httpMethod = "POST"
let postString = "&b=\(item.title)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")};
task.resume()
}
func removeItem(_ item: TodoItem) {
let scheduledNotifications: [UILocalNotification]? = UIApplication.shared.scheduledLocalNotifications
guard scheduledNotifications != nil else {return} // Nothing to remove, so return
for notification in scheduledNotifications! { // loop through notifications...
if (notification.userInfo!["UUID"] as! String == item.UUID) { // ...and cancel the notification that corresponds to this TodoItem instance (matched by UUID)
UIApplication.shared.cancelLocalNotification(notification) // there should be a maximum of one match on UUID
break
}
}
if var todoItems = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) {
todoItems.removeValue(forKey: item.UUID)
UserDefaults.standard.set(todoItems, forKey: ITEMS_KEY) // save/overwrite todo item list
}
}
}
now when I add new post it go to next view but it post not wait the time to post.
3-
import UIKit
class TodoSchedulingViewController: UIViewController {
#IBOutlet weak var titleField: UITextField!
#IBOutlet weak var deadlinePicker: UIDatePicker!
#IBOutlet var info: UITextField!
var inputValue = [index]
#IBAction func savePressed(_ sender: UIButton) {
let todoItem = TodoItem(deadline: deadlinePicker.date, title: info.text!, UUID: UUID().uuidString)
TodoList.sharedInstance.addItem(todoItem) // schedule a local notification to persist this item
let _ = self.navigationController?.popToRootViewController(animated: true) // return to list view
let request = NSMutableURLRequest(url: URL(string: "http://www.xxxxx.php")!)
request.httpMethod = "POST"
let postString = "&b=\(info.text!)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")};
task.resume()
}
}
4-
import UIKit
class TodoTableViewController: UITableViewController {
var todoItems: [TodoItem] = []
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(TodoTableViewController.refreshList), name: NSNotification.Name(rawValue: "TodoListShouldRefresh"), object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
refreshList()
}
func refreshList() {
todoItems = TodoList.sharedInstance.allItems()
if (todoItems.count >= 64) {
self.navigationItem.rightBarButtonItem!.isEnabled = false // disable 'add' button
}
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return todoItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "todoCell", for: indexPath) // retrieve the prototype cell (subtitle style)
let todoItem = todoItems[(indexPath as NSIndexPath).row] as TodoItem
cell.textLabel?.text = todoItem.title as String!
if (todoItem.isOverdue) { // the current time is later than the to-do item's deadline
cell.detailTextLabel?.textColor = UIColor.red
} else {
cell.detailTextLabel?.textColor = UIColor.black // we need to reset this because a cell with red subtitle may be returned by dequeueReusableCellWithIdentifier:indexPath:
}
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "'Due' MMM dd 'at' h:mm a" // example: "Due Jan 01 at 12:00 PM"
cell.detailTextLabel?.text = dateFormatter.string(from: todoItem.deadline as Date)
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true // all cells are editable
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete { // the only editing style we'll support
// Delete the row from the data source
let item = todoItems.remove(at: (indexPath as NSIndexPath).row) // remove TodoItem from notifications array, assign removed item to 'item'
tableView.deleteRows(at: [indexPath], with: .fade)
TodoList.sharedInstance.removeItem(item) // delete backing property list entry and unschedule local notification (if it still exists)
self.navigationItem.rightBarButtonItem!.isEnabled = true // we definitely have under 64 notifications scheduled now, make sure 'add' button is enabled
}
}
}
than you all.
this image
This is my first time using Swift and creating an iOS app and I am having trouble retrieving data from a REST API. I am familiar with Android Development but not iOS.
I am trying to use the API from www.thecocktaildb.com.
An example of a request is http://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita.
I would like to use this request and input a string margarita, or any other drink name, from a search bar and then display the array of drinks into a tableview.
Right now when I run, I am not getting any response from the console.
Am I on the right track?
I am also not sure how to display each result (drink) in a table view cell.
Here is my file:
SearchViewController.swift
class SearchViewController: UIViewController, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TableView: UITableView!
#IBOutlet weak var SearchBar: UISearchBar!
// search in progress or not
var isSearching : Bool = false
override func viewDidLoad() {
super.viewDidLoad()
for subView in self.SearchBar.subviews
{
for subsubView in subView.subviews
{
if let textField = subsubView as? UITextField
{
textField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""))
}
}
}
// set search bar delegate
self.SearchBar.delegate = self
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if self.SearchBar.text!.isEmpty {
// set searching false
self.isSearching = false
}else{
// set searghing true
self.isSearching = true
let postEndpoint: String = "http://www.thecocktaildb.com/api/json/v1/1/search.php?s=" + self.SearchBar.text!.lowercaseString
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling GET on www.thecocktaildb.com")
print(error)
return
}
// parse the result as JSON, since that's what the API provides
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
}
if let strDrink = post["strDrink"] as? String {
print("The drink is: " + strDrink)
}
})
task.resume()
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
// hide kwyboard when search button clicked
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
self.SearchBar.resignFirstResponder()
}
// hide keyboard when cancel button clicked
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.SearchBar.text = ""
self.SearchBar.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Analizyng the json received from GET request with the provided URL http://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita
{
"drinks":[{ ... }]
}
There is a drinks key, so you should navigate to it before trying to access the deeper levels of the json. Also note that the drinks value is an array of JSON and should be cast to [NSDictionary]
The code below should help you get started with it.
if let drinks = post["drinks"] as? [NSDictionary] {
for drink in drinks {
if let strDrink = drink["strDrink"] as? String {
print("The drink is: " + strDrink)
}
}
}