I have a Tab bar Controller to manage all the views. The problem I'm having is when I call a function in searchViewController (doAThing()) from HomeViewController which reloads the tableView in searchViewController, the tableView is empty when the Tab bar controller switches views.
Why does calling the doAThing method in my searchViewController not refresh my tableView?
How can I fill my tableView with values.
HomeViewController.swift
import UIKit
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UISearchBarDelegate{
#IBOutlet weak var productCollectionView: UICollectionView!
#IBOutlet weak var storesCollectionView: UICollectionView!
#IBOutlet var searchQ: UISearchBar!
#IBOutlet weak var scrollView: UIScrollView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(collectionView == storesCollectionView) {
return storesImages.count
}
return productsImages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(collectionView == storesCollectionView) {
let cell2 = storesCollectionView.dequeueReusableCell(withReuseIdentifier: "storesCell", for: indexPath) as! StoreCollectionViewCell
cell2.compstoreImage.image = UIImage(named: storesImages[indexPath.row])
return cell2
}
else{
let cell = productCollectionView.dequeueReusableCell(withReuseIdentifier: "productsCell", for: indexPath) as! ProductCollectionViewCell
cell.pillImage.image = UIImage(named: productsImages[indexPath.row])
return cell
}
}
var productsImages:[String] = ["pcPic", "picturePC"]
var storesImages:[String] = ["newarkStore", "compeStore"]
override func viewDidLoad() {
super.viewDidLoad()
searchQ.delegate = self
scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
// searchQ.delegate = self
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//self.tabBarController?.tabBar.isHidden = false
}
func searchBarSearchButtonClicked(_ searchQ: UISearchBar)
{
print("*********")
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let resultViewController = storyBoard.instantiateViewController(withIdentifier: "SearchViewController") as! searchViewController
// resultViewController.searchQuery = searchQ
resultViewController.doAthing(searchQ)
self.tabBarController?.selectedIndex = 3
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
resultViewController.resultsView.reloadData()
}
// func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
//
// print("*********")
//
// let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "SearchViewController") as! searchViewController
// secondViewController.doAthing(searchBar)
// self.navigationController!.pushViewController(secondViewController, animated: true)
//
//
//
// //let titles: Elements = try doc.select("a[product-thumb]")
// //let titles: String = try doc.select("a").attr("product-thumb")
//
// // print(titles
//
// hideKeyboardWhenTappedAround()
//
// }
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
searchViewController.swift
import UIKit
import SwiftSoup
class searchViewController: UIViewController{
#IBOutlet weak var segmentedControl: UISegmentedControl!
#IBOutlet weak var resultsView: UITableView!
#IBOutlet var searchQuery: UISearchBar!
// let content = try! String(contentsOf: URL(string: "https://www.locally.com/search/all/activities/depts?q=bottle")!)
// let doc: Document = try! SwiftSoup.parse(content)
var products: [String] = []
//let products = ["Computer", "PC", "Laptop"]
let stores = ["Computer Central", "Fry's Electronics", "Best Buy"]
//var stores: [String] = []
let into = ["Custom PC with high performanc. Perfect for gaming and streaming. Great condition", "Custom PC with high performanc. Perfect for gaming and streaming. Great condition", "Custom PC with high performanc. Perfect for gaming and streaming. Great condition"]
var dollars: [String] = []
//let dollars = [100, 220, 129, 100, 220, 129]
let likes = [10, 24, 24, 24 , 456, 46, 46]
//let miles = ["3.2 mi", "4.1 mi", "6.3 mi", "3.2 mi", "4.1 mi", "6.3 mi"]
var miles: [String] = []
// let names = ["Central Computers", "CompE", "geekStore", "Central Computers", "CompE", "geekStore"]
var names: [String] = []
let numbers = ["510-329-0172", "510-456-7345", "510-329-0172", "510-329-0172", "510-456-7345", "510-329-0172"]
var images: [UIImage] = []
var categories: [String] = []
var descriptions: [String] = []
var stars: [String] = []
var ratings: [Double] = []
var ratingImage: [[UIImage]] = [[]]
var phones: [String] = []
var cities: [String] = []
//var webCounter:Int = 0
var x:Double = 0
var y:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "load"), object: nil)
searchQuery.delegate = self
resultsView.delegate = self
resultsView.dataSource = self
//set the height of each row in tableview
self.resultsView.rowHeight = 200.0
// Do any additional setup after loading the view.
}
#objc func loadList(notification: NSNotification) {
//load data here
self.resultsView.reloadData()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
//searchBar.inputViewController?.dismissKeyboard()
searchBar.inputViewController?.dismiss(animated: true)
doAthing(searchBar)
self.searchQuery.endEditing(true)
self.resultsView.keyboardDismissMode = .onDrag
hideKeyboardWhenTappedAround()
}
func doAthing(_ searchBar: UISearchBar) {
do {
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.style = UIActivityIndicatorView.Style.medium
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: true, completion: nil)
print("reached here")
let html = try String(contentsOf: URL(string: "https://www.locally.com/search/all/activities/depts?q=" + searchBar.text!)!)
//let doc: Document = try SwiftSoup.parse(html)
guard let titles: Elements = try? SwiftSoup.parse(html).getElementsByClass("product-thumb ") else {return}//select("a") else {return}
guard let prices: Elements = try? SwiftSoup.parse(html).getElementsByClass("product-thumb-price dl-price") else {return}
guard let Stores: Elements = try? SwiftSoup.parse(html).getElementsByClass("filter-label-link") else {return}
guard let Images: Elements = try? SwiftSoup.parse(html).getElementsByClass("product-thumb-img") else {return}
products = []
miles = []
dollars = []
names = []
images = []
stars = []
for title: Element in titles.array() {
print("title" + String(titles.size()))
products.append(try! title.attr("data-product-name"))
guard let url: URL = try? URL(string: "https://www.locally.com/" + String(try! title.attr("href")))
else
{
miles.append("-")
continue
}
let html1 = try String(contentsOf: url)
guard let distances: Element = try? SwiftSoup.parse(html1).getElementsByClass("conv-section-distance dl-store-distance").first()
else
{
miles.append("-")
continue
}
print(try! distances.ownText())
miles.append(try! distances.ownText())
guard let K: Array<String> = try? SwiftSoup.parse(html1).getElementsByClass("breadcrumbs container").eachText() else {return}
let str = (try! K.last!.components(separatedBy: "/") )
categories.append(str[str.count - 2])
print(str[str.count - 2])
guard let desc: Array<String> = try? SwiftSoup.parse(html1).getElementsByClass("pdp-information").eachText() else {return}
guard let s:String = try? desc[1]
else {
return
}
descriptions.append( String( s.suffix(s.count - 19) ) )
print( String( s.suffix(s.count - 19) ) )
guard let star: Element = try? SwiftSoup.parse(html1).getElementsByClass("stars").first()
else
{
print("no reviews")
ratings.append(0)
continue
}
print(try! star.attr("data-rating"))
//ratings.append(try! star.attr("data-rating")) ?? ()
let x = Double(try! star.attr("data-rating")) ?? 0
print("y: " + String(Int(x)))
ratings.append(x)
guard let locations: Element = try? SwiftSoup.parse(html1).getElementsByClass("conv-section-store-address section-subtitle dl-store-address js-store-location").first()
else
{
print("cant find city")
return
}
let string = locations.ownText()
print("location: " + String(string.prefix(string.count - 10)) )
cities.append(try! String(string.prefix(string.count - 10)))
guard let phoneNums: Element = try? SwiftSoup.parse(html1).getElementsByClass("selected-retailer-info-link btn-action-sm tooltip").first()
else
{
print("link not found")
return
}
guard let urls:URL = try? URL(string: "https://www.locally.com/" + phoneNums.attr("href") )
else
{
return
}
let html2 = try String(contentsOf: urls )
guard let storePage:Element = try? SwiftSoup.parse(html2).getElementsByClass("landing-page-phone-label").first() else {
print("Phone Number not found")
return
}
let sp = try? storePage.ownText
if let s = sp {
phones.append(try! s())
}
else {
phones.append("N/A")
}
print(try! storePage.ownText())
//
// let html1 = try String(contentsOf: url)
}
for price: Element in prices.array() {
print("prices" + String(prices.size()))
print(String(try! price.ownText()))
dollars.append(try! price.ownText())
}
for store: Element in Stores.array() {
print("Stores" + String(Stores.size()))
names.append(try! store.ownText()) ?? names.append("N/A")
}
for image: Element in Images.array() {
guard let url = URL(string: try! image.attr("src") ) else { return }
let data = try? Data(contentsOf: url)
if let imageData = data {
images.append( UIImage(data: imageData)! )
}
else {
images.append(UIImage(named: "pcPic")!)
}
//images.append(try! image.downloaded(from: image.attr("src")))
}
dismiss(animated: false, completion: nil)
resultsView.reloadData()
//let titles: Elements = try doc.select("a[product-thumb]")
//let titles: String = try doc.select("a").attr("product-thumb")
// print(titles)
} catch Exception.Error(type: let type, Message: let message) {
print(type)
print(message)
} catch {
print("")
}
}
// override func viewWillAppear(_ animated: Bool) {
// super.viewWillAppear(animated)
// self.tabBarController?.tabBar.isHidden = false
// }
//When user changes segment, tableview is reloaded
#IBAction func segmentChanged(_ sender: Any) {
resultsView.reloadData();
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
func imageWithImage(image: UIImage, scaledToSize newSize: CGSize) -> UIImage {
UIGraphicsBeginImageContext(newSize)
image.draw(in: CGRect(x: 0 ,y: 20 ,width: newSize.width ,height: newSize.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!.withRenderingMode(.alwaysOriginal)
}
}
extension searchViewController: UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("reached here")
switch segmentedControl.selectedSegmentIndex {
case 0:
return products.count
case 1:
return stores.count
case 2:
return (products.count + stores.count)
default:
break
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultsTableViewCell") as! resultsTableViewCell
switch segmentedControl.selectedSegmentIndex {
case 0:
cell.titleLabel?.text = products[indexPath.row]
cell.productImage?.image = images[indexPath.row]
// cell.descriptionLabel?.text = into[indexPath.row]
// cell.descriptionLabel?.numberOfLines = 0
cell.price?.text = String(dollars[indexPath.row])
cell.distance?.text = miles[indexPath.row]
cell.storeName?.numberOfLines = 0
cell.storeName?.text = names[indexPath.row]
cell.phoneNumber?.text = phones[indexPath.row]
let ratNumber = ratings[indexPath.row]
if( ratNumber == 0 )
{
cell.rating?.text = "No Reviews"
}
else
{
cell.rating?.text = String(ratNumber)
}
if(ratNumber > 4.5)
{
cell.star1.image = UIImage(named: "regular_5")
}
else if(ratNumber > 4.0)
{
cell.star1.image = UIImage(named: "regular_4_half")
}
else if(ratNumber == 4.0)
{
cell.star1.image = UIImage(named: "regular_4")
}
else if(ratNumber > 3.0)
{
cell.star1.image = UIImage(named: "regular_3_half")
}
else if(ratNumber == 3.0)
{
cell.star1.image = UIImage(named: "regular_3")
}
else if(ratNumber > 2.0)
{
cell.star1.image = UIImage(named: "regular_2_half")
}
else if(ratNumber == 2.0)
{
cell.star1.image = UIImage(named: "regular_2")
}
else if(ratNumber > 1.0)
{
cell.star1.image = UIImage(named: "regular_1_half")
}
else if(ratNumber == 1.0)
{
cell.star1.image = UIImage(named: "regular_1")
}
else
{
cell.star1.image = UIImage(named: "regular_0")
}
cell.rating?.numberOfLines = 0
// cell.phoneNumber?.text = numbers[indexPath.row]
case 1:
cell.titleLabel?.text = stores[indexPath.row]
cell.productImage?.image = imageWithImage(image: UIImage.init(named: "pcPic")!, scaledToSize: CGSize(width: 400, height: 300))
// cell.descriptionLabel?.text = into[indexPath.row]
// cell.descriptionLabel?.numberOfLines = 0
cell.price?.text = String(dollars[indexPath.row])
cell.distance?.text = miles[indexPath.row]
cell.storeName?.text = names[indexPath.row]
cell.phoneNumber?.text = numbers[indexPath.row]
case 2:
var all = products + stores
all.shuffle()
let alls = into + into
cell.titleLabel?.text = all[indexPath.row]
cell.productImage?.image = imageWithImage(image: UIImage.init(named: "pcPic")!, scaledToSize: CGSize(width: 400, height: 300))
// cell.descriptionLabel?.text = alls[indexPath.row]
// cell.descriptionLabel?.numberOfLines = 0
cell.price?.text = String(dollars[indexPath.row])
cell.distance?.text = miles[indexPath.row]
cell.storeName?.text = names[indexPath.row]
cell.phoneNumber?.text = numbers[indexPath.row]
default:
break
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// let vc = self.storyboard?.instantiateViewController(withIdentifier: "ShopViewController") as! ShopViewController
// self.present(vc, animated: true, completion: nil)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationVC = storyboard.instantiateViewController(withIdentifier: "ProductViewController") as! ProductViewController
destinationVC.ktitle = products[indexPath.row]
destinationVC.kprice = dollars[indexPath.row]
// destinationVC.kdescription = [indexPath.row]
destinationVC.kimage = images[indexPath.row]
// destinationVC.klikes = likes[indexPath.row]
destinationVC.kcategory = categories[indexPath.row]
destinationVC.kdescription = descriptions[indexPath.row]
destinationVC.kname = names[indexPath.row]
destinationVC.kmiles = miles[indexPath.row]
destinationVC.klocation = cities[indexPath.row]
self.present(destinationVC, animated: true, completion: nil)
}
}
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard(_:)))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard(_ sender: UITapGestureRecognizer) {
view.endEditing(true)
if let nav = self.navigationController {
nav.view.endEditing(true)
}
}
}
First, it's probably not a good idea to switch to a different tab in that manner. Users understand that tapping a tab-bar icon/button takes them to a new tab. If you're jumping around in the tabs via code, it can be very confusing for the user.
But... it's your app.
The reason your code does not "refresh my tableView" is because you never actually reference that view controller.
In your code:
func searchBarSearchButtonClicked(_ searchQ: UISearchBar)
{
print("*********")
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
// here you create a NEW instance of searchViewController
let resultViewController = storyBoard.instantiateViewController(withIdentifier: "SearchViewController") as! searchViewController
// you call a func in that instance
resultViewController.doAthing(searchQ)
// you switch to tab index 3, which holds an OLD instance of searchViewController
self.tabBarController?.selectedIndex = 3
// you tell resultsView in the NEW instance to reloadData()
resultViewController.resultsView.reloadData()
// as soon as you exit this func, the NEW instance is deleted
}
You could do something like this:
func searchBarSearchButtonClicked(_ searchQ: UISearchBar)
print("*********")
// get a reference to the searchViewController that is already
// part of the tab bar controller
if let tb = self.tabBarController,
let controllers = tb.viewControllers,
let resultVC = controllers[3] as? searchViewController {
// call the func
resultVC.doAthing("new")
tb.selectedIndex = 3
}
}
However, that's really not a great approach... Just for one example, Suppose you change the order of the tabs at some point?
You're better off using either a custom tab bar controller class, or using a "data manager" class.
I'd suggest you head over to google (or your favorite search engine) and search for swift pass data between tab bar view controllers -- you'll find plenty of discussions, articles, examples, etc.
Edit -- comment
In HomeViewController replace your func searchBarSearchButtonClicked with this:
func searchBarSearchButtonClicked(_ searchQ: UISearchBar)
{
print("1 - searchBarSearchButtonClicked")
guard let btnTitle = searchQ.largeContentTitle else {
print("2 - FAILED to get searchQ.largeContentTitle")
return
}
print("2 - got btnTitle", btnTitle)
if let tb = self.tabBarController {
print("3 - got a tab bar controller reference")
if let controllers = tb.viewControllers {
print("4 - got controllers reference")
if controllers.count == 4 {
print("5 - we have 4 controllers")
if let resultVC = controllers[3] as? searchViewController {
print("6 - got a reference to searchViewController")
// if we have not yet selected the 4th tab,
// the view will not yet have been loaded
// so make sure it is
resultVC.loadViewIfNeeded()
// call the func, passing the button title
resultVC.doAthing(searchQ)
// switch to the 4th tab
tb.selectedIndex = 3
print("7 - we should now be at searchViewController")
} else {
print("6 - FAILED TO GET a reference to searchViewController")
}
} else {
print("5 - FAILED TO GET a reference to searchViewController")
}
} else {
print("4 - FAILED TO GET a reference to searchViewController")
}
} else {
print("3 - FAILED TO GET a reference to searchViewController")
}
}
Then see what messages get printed to the debug console.
Related
I am getting this error when trying to save a string to coreData inside my newJobNote class. It seems to crash in the function private func createNote() on the line let tuple = CoreDataManager.shared.createJobNote(jobNote: jobNote, job: job)
This is the error:
2018-05-03 17:37:53.180012+0100 Shoot[7022:3228759] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "note"; desired type = NSString; given type = JobNote; value = (entity: JobNote; id: 0x1c002f080 ; data: {
job = "0xd000000000580000 ";
note = nil;
}).'
I have an entity named Job that stores a job name - I am then passing this through to my JobNoteVC.
I also have an entity named: JobNote with an attribute named: note. I have also made a structure for my core data:
func createJobNote(jobNote: String, job: Job) -> (JobNote?, Error?) {
let context = persistentContainer.viewContext
// create note
let jobNote = NSEntityDescription.insertNewObject(forEntityName: "JobNote", into: context) as! JobNote
jobNote.job = job
jobNote.setValue(jobNote, forKey: "note")
do {
try context.save()
return (jobNote, nil)
} catch let error {
print ("Failed to add camera:", error)
return (nil, error)
}
}
I then have a note page that contains a tableView that will display all notes that are stored in coredata:
import UIKit
import CoreData
class notes : UIViewController, UITableViewDelegate, UITableViewDataSource, NewJobNoteControllerDelegate {
let cellId = "cellId"
var tableView = UITableView()
var jobNotesArray = [JobNote]()
var job: Job? {
let tabBarController = self.tabBarController as! jobTabController
return tabBarController.job
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.navigationItem.title = "NOTES"
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(HandleNewNote))
self.tabBarController?.navigationItem.rightBarButtonItems = [addButton]
addTableView()
fetchJobNotes()
}
func addTableView() {
// TABLE VIEW SETUP
tableView.frame = self.view.frame
self.view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
}
private func fetchJobNotes(){
guard let jobNotes = job?.jobNotes?.allObjects as? [JobNote] else { return }
self.jobNotesArray = jobNotes
}
func didAddJobNote(jobNote: JobNote) {
jobNotesArray.append(jobNote)
tableView.reloadData()
}
func didEditJobNote(jobNote: JobNote) {
let row = jobNotesArray.index(of: jobNote)
let reloadIndexPath = IndexPath(row: row!, section: 0)
tableView.reloadRows(at: [reloadIndexPath], with: .middle)
}
#IBAction func HandleNewNote(sender : UIButton) {
let newNote = newJobNote()
newNote.delegate = self
newNote.job = job
let navController = UINavigationController(rootViewController: newNote)
present(navController, animated: true, completion: nil)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return jobNotesArray.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
return cell
}
}
This is my newNoteVC:
import CoreData
protocol NewJobNoteControllerDelegate {
func didAddJobNote(jobNote : JobNote)
func didEditJobNote(jobNote: JobNote)
}
class newJobNote: UIViewController {
var delegate: NewJobNoteControllerDelegate?
var job: Job?
let noteLabel: UILabel = {
let label = UILabel()
label.text = "NOTE"
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor(red:0.63, green:0.63, blue:0.63, alpha:1.0)
return label
}()
var noteTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Enter Note..."
textField.tintColor = UIColor(red:0.87, green:0.30, blue:0.32, alpha:1.0)
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
var jobNote : JobNote? {
didSet {
noteTextField.text = jobNote?.note
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
let backButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(HandleBack))
navigationItem.leftBarButtonItem = backButton
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationItem.title = "NEW NOTE"
}
private func createNote() {
guard let jobNote = noteTextField.text else { return }
guard let job = self.job else { return }
let tuple = CoreDataManager.shared.createJobNote(jobNote: jobNote, job: job)
if let error = tuple.1 {
print(error)
} else {
dismiss(animated: true, completion: {
self.delegate?.didAddJobNote(jobNote: tuple.0!)
})
}
}
private func saveNoteChanges() {
let context = CoreDataManager.shared.persistentContainer.viewContext
jobNote?.note = noteTextField.text
do {
try context.save()
dismiss(animated: true) {
self.delegate?.didEditJobNote(jobNote: self.jobNote!)
}
} catch let error {
print ("Failed to save camera changes:", error)
}
}
#IBAction private func HandleBack(sender : UIButton) {
if jobNote == nil {
createNote()
print("back to note and saved")
} else {
saveNoteChanges()
print("back to note and saved")
}
}
}
The problem is here
jobNote.setValue(jobNote, forKey: "note")
you can't set entity instance to an attribute inside the entity itself , change parameter name
func createJobNote(sendedNote: String, job: Job) -> (JobNote?, Error?) {
let context = persistentContainer.viewContext
// create note
let jobNote = NSEntityDescription.insertNewObject(forEntityName: "JobNote", into: context) as! JobNote
jobNote.job = job
jobNote.setValue(sendedNote, forKey: "note")
do {
try context.save()
return (jobNote, nil)
} catch let error {
print ("Failed to add camera:", error)
return (nil, error)
}
}
I am a beginner to Xcode and Swift and I am currently creating an application where the user adds a person on the application and after that it right the amount of money they owe that person or that person owes him/her.
Note: I have used core data to store all the value
I actually want to change the value of a variable when switch is on and off. For instance, in the following I want the "amount" to be negative when the switch is on and positive when it is off. Also, when I try to do this and send amount variable to previous view controller I can't send the value depending on the UISwitch because it always shows positive. I am trying to find a solution to this from past 3 days therefore can you please help me? Thanks a lot in advance
Owe ViewController
import UIKit
class NewOweTableViewController: UIViewController {
#IBOutlet weak var titleTextField: UITextField!
#IBOutlet weak var locationTextField: UITextField!
#IBOutlet weak var amountTextField: UITextField!
#IBOutlet weak var datePicker: UIDatePicker!
let context = (UIApplication.shared.delegate as!
AppDelegate).persistentContainer.viewContext
var owe: Owe?
var dataInfo: [Owe] = []
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.viewWithTag(1)?.isHidden = true
let saveBTN = UIBarButtonItem(barButtonSystemItem:UIBarButtonSystemItem.save, target:self,
action: #selector(saveButtonTapped(_:)))
let deleteBTN = UIBarButtonItem(barButtonSystemItem:UIBarButtonSystemItem.trash, target:self,
action: #selector(deleteButtonTapped(_:)))
self.navigationItem.rightBarButtonItems = [saveBTN, deleteBTN]
if !dataInfo.isEmpty {
titleTextField.text = dataInfo[0].name
amountTextField.text = (NSString(format: "%.2f", (dataInfo[0].amount) as CVarArg) as String)
locationTextField.text = dataInfo[0].location
datePicker.date = dataInfo[0].date!
}
}
#objc func saveButtonTapped(_ sender: UIButton){
if !dataInfo.isEmpty{
let data = dataInfo[0]
data.name = titleTextField.text
data.amount = Double(amountTextField.text!)!
data.location = locationTextField.text
data.date = datePicker.date
}
else if titleTextField.text == "" || amountTextField.text == "" || locationTextField.text == "" {
return
}
else{
let data = Owe(context: context)
data.name = titleTextField.text
data.amount = Double(amountTextField.text!)!
data.location = locationTextField.text
data.date = datePicker.date
}
do {
try context.save()
navigationController?.popViewController(animated: true)
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
#objc func deleteButtonTapped(_ sender: UIButton){
if !dataInfo.isEmpty{
let data = dataInfo[0]
context.delete(data)
do {
try context.save()
navigationController?.popViewController(animated: true)
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
#IBAction func oweSwitch(_ sender: UISwitch) {
if sender.isOn {
owe?.amount = (owe?.amount)! * (-1)
amountTextField.textColor = UIColor.green
} else {
owe?.amount = (owe?.amount)! * (1)
amountTextField.textColor = UIColor.red
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Previous View Controller
import UIKit
class PersonDetailTableViewController: UITableViewController {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var totalLabel: UILabel?
var person: People?
var owe: Owe?
#IBOutlet var personTable: UITableView!
var dataInfo: [Owe] = []
var selectedObject: [Owe] = []
var balanceAmount = "Balance: "
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dataInfo.count)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = personTable
.dequeueReusableCell(withIdentifier: "detailsCell", for: indexPath)
cell.textLabel?.text = dataInfo[indexPath.row].name
cell.detailTextLabel?.text = "₹ \(dataInfo[indexPath.row].amount)"
if dataInfo[indexPath.row].amount < 0 {
cell.detailTextLabel?.textColor = UIColor.red
} else {
cell.detailTextLabel?.textColor = UIColor.green
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedObject = [dataInfo[indexPath.row]]
performSegue(withIdentifier: "addOweDetails", sender: nil)
tableView.deselectRow(at: indexPath, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
getData()
personTable.dataSource = self
addTotalToNav()
print(dataInfo as Any)
}
// MARK: - Table view data source
func addTotalToNav() -> Void {
if let navigationBar = self.navigationController?.navigationBar {
let totalFrame = CGRect(x: 10, y: 0, width: navigationBar.frame.width/2, height: navigationBar.frame.height)
totalLabel = UILabel(frame: totalFrame)
totalLabel?.text = balanceAmount
totalLabel?.tag = 1
totalLabel?.font = UIFont.boldSystemFont(ofSize: 14)
totalLabel?.textColor = UIColor.red
// navigationBar.large = totalLabel?.text
self.title = totalLabel?.text
}
}
func getData() -> Void {
do{
dataInfo = try context.fetch(Owe.fetchRequest())
var total:Double = 0.00
for i in 0 ..< dataInfo.count {
total += dataInfo[i].amount as! Double
}
balanceAmount = "Balance: ₹" + (NSString(format: "%.2f", total as CVarArg) as String)
}
catch{
print("Fetching Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NewOweTableViewController
vc.dataInfo = selectedObject
selectedObject.removeAll()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
getData()
personTable.reloadData()
if (self.navigationController?.navigationBar.viewWithTag(1)?.isHidden == true){
self.navigationController?.navigationBar.viewWithTag(1)?.removeFromSuperview()
addTotalToNav()
}
}
}
Core Data for owe
import UIKit
import CoreData
#objc(Owe)
public class Owe: NSManagedObject {
var date: Date? {
get{
return rawDate as Date?
}
set {
rawDate = newValue as NSDate?
}
}
convenience init?(name: String?, location: String?, amount: Double, date: Date?) {
let appDelegate = UIApplication.shared.delegate as? AppDelegate
guard let context = appDelegate?.persistentContainer.viewContext
else {
return nil
}
self.init(entity: Owe.entity(), insertInto: context)
self.name = name
self.location = location
self.amount = amount
self.date = date
}
}
Hi there and welcome to the Swift Community!
If I understand correctly, you are trying to propagates updates backwards from NewOweTableViewController to PersonDetailTableViewController. If that is the case, an easy way to achieve this with your MVC architecture is by passing a closure to NewOweTableViewController when you initialize it in PersonDetailTableViewController.
In order to do so,
Update NewOweTableViewController and add a closure property.
class NewOweTableViewController: UIViewController {
// ...
var switchValueUpdate: ((Bool) -> ())?
// ...
}
Make sure you call this closure inside your #IBAction that you link to your switch in NewOweTableViewController
#IBAction func oweSwitch(_ sender: UISwitch) {
if sender.isOn {
owe?.amount = (owe?.amount)! * (-1)
amountTextField.textColor = UIColor.green
} else {
owe?.amount = (owe?.amount)! * (1)
amountTextField.textColor = UIColor.red
}
switchValueUpdate?(sender.isOn)
}
update PersonDetailTableViewController to set the closure
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NewOweTableViewController
vc.dataInfo = selectedObject
selectedObject.removeAll()
vc.switchValueUpdate = { (isOn) in
// Here you go, update PersonDetailTableViewController to reflect changes related to the switch!
}
}
That's it! Let me know if you have any question on that code, hope it helps!
I am programming an application and it is supposed to go to another view controller on a button press but instead it crashes when I run it. The editor shows this: and with editor breakpointing on it shows this: but there is no error in the console. Here is the code for the viewcontroller that does the segue:
//
// DoTodayViewController.swift
// Paley Foundation: Starfish Support
//
// Created by Sa'ar Lipshitz on 10/28/17.
//
import UIKit
class DoTodayViewController: UIViewController {
#IBOutlet weak var navItem: UINavigationItem!
#IBOutlet weak var getBtn: UIButton!
#IBOutlet weak var suggestBtn: UIButton!
var name = "Sa'ar"
override func viewDidLoad() {
super.viewDidLoad()
getBtn.layer.cornerRadius = 8
getBtn.clipsToBounds = true
suggestBtn.layer.cornerRadius = 8
suggestBtn.clipsToBounds = true
navItem.prompt = "What would you like to do today, "+name+"?"
}
#IBAction func suggest(_ sender: Any) {
let vc = storyboard?.instantiateViewController(withIdentifier: "SuggestViewController") as! SuggestViewController
navigationController?.pushViewController(vc, animated: true)
}
//This crashes my app:
#IBAction func get(_ sender: Any) {
let vc = storyboard?.instantiateViewController(withIdentifier: "AccessViewController") as! AccessViewController
navigationController?.pushViewController(vc, animated: true)
}
}
and here is my code for the viewcontroller that gets opened:
//
// AccessViewController.swift
// Paley Foundation: Starfish Support
//
// Created by Sa'ar Lipshitz on 10/29/17.
//
import UIKit
import Firebase
import Material
class AccessViewController: UIViewController {
var adviceRef: DatabaseReference!
var advice: [[String: Any]] = []
var i = 0
var card: Card!
var loadingLbl: UILabel!
var panGesture = UIPanGestureRecognizer()
var cardOrigPos: CGPoint!
override func viewDidLoad() {
super.viewDidLoad()
adviceRef = Database.database().reference().child("Advice")
var advDict: NSDictionary?
adviceRef.observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
advDict = value
print(advDict as Any)
for (_, adv) in advDict! {
self.advice.append(adv as! [String : Any])
}
print(self.advice)
self.showNextCard()
}) { (error) in
print(error.localizedDescription)
}
let swipeRec = UIPanGestureRecognizer(target: self, action: #selector(swipe(sender:)))
card.isUserInteractionEnabled = true
card.addGestureRecognizer(swipeRec)
}
#objc func swipe(sender: UIPanGestureRecognizer) {
let translation = sender.translation(in: view)
let velocity = sender.velocity(in: view)
let direction = velocity
print("Translation: \(translation)")
if sender.state == .began {
cardOrigPos = card.center
} else if sender.state == .changed {
card.center = CGPoint(x: cardOrigPos.x+translation.x, y: cardOrigPos.y+translation.y)
} else if sender.state == .ended {
if velocity.y == 0 && velocity.x == 0 {
UIView.animate(withDuration: 0.3, animations: {
self.card.center = self.view.center
})
} else {
UIView.animate(withDuration: 0.3, animations: {
self.card.center = CGPoint(x: self.cardOrigPos.x+direction.x*5, y: self.cardOrigPos.y+direction.y)
})
self.showNextCard()
}
}
}
func showNextCard() {
if advice.count >= 0 {
let adv = advice[i]
setCard(adv["username"] as? String, adv["title"] as! String, adv["desc"] as! String, image: adv["image"] as? UIImage)
i += 1
if i >= advice.count {
i = 0
}
}
}
func setCard(_ username: String?, _ title: String, _ desc: String, image: UIImage?) {
let toolbar = setToolbar(username ?? "", title)
card = Card()
card.toolbar = toolbar
card.toolbarEdgeInsetsPreset = .square3
card.toolbarEdgeInsets.bottom = 0
card.toolbarEdgeInsets.right = 8
card.contentView = setContentView(content: desc)
card.contentViewEdgeInsetsPreset = .wideRectangle3
card.layer.borderWidth = 1.0
card.layer.borderColor = UIColor.black.cgColor
card.layer.cornerRadius = 2
view.layout(card).horizontally(left: 20, right: 20).center()
}
func setToolbar(_ username: String, _ title: String) -> Toolbar {
let toolbar = Toolbar(rightViews: [setMoreBtn()])
toolbar.title = title
toolbar.detail = username
toolbar.detailLabel.textColor = Color.grey.base
return toolbar
}
func setMoreBtn() -> IconButton {
let moreBtn = IconButton(image: Icon.cm.moreVertical, tintColor: Color.grey.base)
return moreBtn
}
func setContentView(content: String) -> UILabel {
let contentView = UILabel()
contentView.numberOfLines = 0
contentView.text = content
contentView.font = RobotoFont.regular(with: 14)
return contentView
}
}
When I tried using print statements to debug, the one in the DoTodayViewController.get(_ sender: Any) method ran but not the one in AccessViewController.viewDidLoad()
Make sure you changed the class of the view controller object in the storyboard to AccessViewController and that the Storyboard ID is correctly spelled. You may be encountering a nil when trying to force unwrap storyboard?.instantiateViewController(withIdentifier: "AccessViewController") as! AccessViewController. Try using if let wherever an optional needs to be unwrapped to handle the scenario of it being nil.
When a specific event happens(in my case when a tab bar is changed) I want to create a new link from an Array. I have gotten this to work but the problem I am not facing is when i try to pass the generated link to the same viewcontroller i get an error
fatal error: unexpectedly found nil while unwrapping an Optional value
This happens when I try to change the UILabel movietitle and imageview. I think this is because every time it sends the link it creates a new ViewController instead of using the existing one. Might also be that i have missed an unwrapped value somewhere. Hope someone here can help me!
StringBuilder:
import UIKit
class StringBuilder: NSObject {
let urlString = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acb9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=12"
let urlStringMultipleGenres = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbf5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=28,12,10749"
var currentGenreArray: Array<Int> = []
//This will be run after the user has selected or deselected genres in the genreControllerView
func updateGenres(genreArrayIn: Array<Int>){
print("update genres input: ")
print(genreArrayIn)
//If new array input is the same as old arrayinput, do nothing
if genreArrayIn == currentGenreArray{
return
}
else{
let returnedLink = generateString(genreID: genreArrayIn)
print("Returned link after generate string" + returnedLink)
sendLink(link: returnedLink)
}
}
//After the updated genres have been put into an Array, this function will generate the whole string which
//will be the main String the getMovieRequest follows
func generateString(genreID: Array<Int>) -> String{
let filteredGenreArray = filterZeroes(unfilteredArray: genreID)
currentGenreArray = genreID
print("current genre array: ")
print(currentGenreArray)
let baseString = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbfed4ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres="
var generatedString = baseString
for id in filteredGenreArray{
let k = String(id)
generatedString += k + ","
}
print("Generated Link from Strinbuilder: ")
print(generatedString)
return generatedString
}
func filterZeroes(unfilteredArray: Array<Int>) -> Array<Int>{
let filteredGenreArray = unfilteredArray.filter {$0 > 0}
print("filtered array: ")
print(filteredGenreArray)
return filteredGenreArray
}
func sendLink(link: String){
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let movieVC = storyBoard.instantiateViewController(withIdentifier: "movieView") as! ViewController
movieVC.getMovieData(activeGenreLink: link)
print("new link sent from sendlink()")
}
}
ViewController:
import UIKit
import Alamofire
import AlamofireImage
class ViewController: UIViewController{
static let sharedInstance = ViewController()
var movieIndex = 0
var movieArray:[Movie] = []
var downloadGrp = DispatchGroup()
#IBOutlet var uiMovieTitle: UILabel!
#IBOutlet var uiMoviePoster: UIImageView!
#IBOutlet var posterLoading: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let firstTimeLink = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acb9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=35,18"
getMovieData(activeGenreLink: firstTimeLink)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
uiMoviePoster.isUserInteractionEnabled = true
uiMoviePoster.addGestureRecognizer(tapGestureRecognizer)
print("settings Sucessful")
}
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer){
performSegue(withIdentifier: "detailsSegue", sender: self)
}
#IBAction func yesBtn(_ sender: UIButton) {
movieIndex += 1
updateUI()
}
#IBAction func seenBtn(_ sender: UIButton) {
movieIndex += 1
}
#IBAction func noBtn(_ sender: UIButton) {
movieIndex += 1
}
//Get movie data
func getMovieData(activeGenreLink: String){
//self.posterLoading.startAnimating()
movieIndex = 0
self.downloadGrp.enter()
Alamofire.request(activeGenreLink).responseJSON { response in
//print(response.request) // original URL request
//print(response.response) // HTTP URL response
//print(response.data) // server data
//print(response.result) // result of response serialization
self.movieArray = []
print(self.movieArray)
if let json = response.result.value as? Dictionary<String,AnyObject> {
if let movies = json["results"] as? [AnyObject]{
for movie in movies{
let movieObject: Movie = Movie()
let title = movie["title"] as! String
let releaseDate = movie["release_date"] as! String
let posterPath = movie["poster_path"] as! String
let overView = movie["overview"] as! String
let movieId = movie["id"] as! Int
let genre_ids = movie["genre_ids"] as! [AnyObject]
movieObject.title = title
movieObject.movieRelease = releaseDate
movieObject.posterPath = posterPath
movieObject.overView = overView
movieObject.movieId = movieId
for genre in genre_ids{//Genre ids, fix this
movieObject.movieGenre.append(genre as! Int)
}
Alamofire.request("http://image.tmdb.org/t/p/w1920" + posterPath).responseImage {
response in
//print(response.request)
//print(response.response)
//debugPrint(response.result)
if var image = response.result.value {
image = UIImage(data: response.data!)!
movieObject.poster = image
}
}
self.movieArray.append(movieObject)
}//End of for each movie
}
else{
print("error while making results anyobject")
}
}
else{
print("error while trying to make NSDictionary")}
self.downloadGrp.leave()
}//End of Json request
downloadGrp.notify( queue: .main){
print("all downloads finished")
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
print(self.movieArray[0].title!)
self.updateUI()
print("updatedUI")
}
}
}//End of getmoviedata
override func prepare(for segue: UIStoryboardSegue,sender: Any?){
// Create a variable that you want to send
let currentMovie = self.movieArray[movieIndex]
if let destinationVC = segue.destination as? DetailsViewController{
destinationVC.currentMovie = currentMovie
}
}
func updateUI(){
//self.posterLoading.stopAnimating()
if uiMoviePoster == nil{
print(uiMovieTitle.debugDescription)
}
else{
print("first time debugID: " + uiMovieTitle.debugDescription)
uiMovieTitle.text = self.movieArray[movieIndex].title
uiMoviePoster.image = self.movieArray[movieIndex].poster
}
}
}
You want to grab a sharedInstance not instantiate from a storyboard
let movieVC = ViewController.sharedInstance()
but I still do not understand why do you need to do it like this
In Root view, I used Tabbar controller and there are 4 tabs.
At first tab View(index = 0), user can search books on open Book API services. It works well, but here is a problem.
1. Users search a book on first tab view (index = 0,tableview)
2. The results come out
3. Users tab other tab button and move other views.
4. Users tab a first button(index=0,table view) for backing to search other books.
5. The Black screen shows up in first tab view, but the user can move to other views by tapping other tabs, there are no black screens. There is a black screen only in the first view(index=0)
What's the problem with my app?
I coded my app with swift.
import Foundation
import UIKit
class SearchHome: UITableViewController, UISearchBarDelegate, UISearchControllerDelegate{
// MARK: - Properties
let searchController = UISearchController(searchResultsController: nil)
// var barButton = UIBarButtonItem(title: "search", style: .Plain, target: nil, action: nil)
let apiKey : String = "cbccaa3f----d980b0c"
var searchString : String = ""
var list = Array<BookAPIresult>()
// MARK: - View Setup
override func viewDidLoad() {
super.viewDidLoad()
self.searchController.searchBar.text! = ""
// Setup the Search Controller
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.Prominent
searchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = searchController.searchBar
// Setup the Scope Bar
searchController.searchBar.scopeButtonTitles = ["title", "hashtag"]
searchController.searchBar.placeholder = "book search"
// Setup Animation for NavigationBar
navigationController?.hidesBarsOnSwipe = true
searchController.hidesNavigationBarDuringPresentation = false
navigationController?.hidesBarsWhenKeyboardAppears = false
navigationController?.hidesBarsOnTap = true
navigationController?.hidesBarsWhenVerticallyCompact = true
self.refreshControl?.addTarget(self, action: #selector(SearchHome.handleRefresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
// declare hide keyboard tap
let hideTap = UITapGestureRecognizer(target: self, action: #selector(SearchHome.hideKeyboardTap(_:)))
hideTap.numberOfTapsRequired = 1
self.view.userInteractionEnabled = true
self.view.addGestureRecognizer(hideTap)
// declare hide keyboard swipe
let hideSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SearchHome.hideKeyboardSwipe(_:)))
self.view.addGestureRecognizer(hideSwipe)
}
// MARK: - UISearchBar Delegate
func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
// filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar){
self.searchString = self.searchController.searchBar.text!
self.list.removeAll()
self.callBookAPI()
self.tableView.reloadData()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.list.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let row = self.list[indexPath.row]
NSLog("title:\(row.title),row:\(indexPath.row), author:\(row.author)")
let cell = tableView.dequeueReusableCellWithIdentifier("ListCell") as! BookAPIResultCell
cell.title?.text = row.title
cell.author?.text = row.author
dispatch_async(dispatch_get_main_queue(),{ cell.thumb.image = self.getThumbnailImage(indexPath.row)})
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
NSLog("%d",indexPath.row)
}
override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.view.endEditing(false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func callBookAPI(){
let encodedSearchString = searchString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let apiURI = NSURL(string: "https://apis.daum.net/search/book?apikey=\(self.apiKey)&q=\(encodedSearchString!)&searchType=title&output=json")
let apidata : NSData? = NSData(contentsOfURL: apiURI!)
NSLog("API Result = %#", NSString(data: apidata!, encoding: NSUTF8StringEncoding)!)
do {
let data = try NSJSONSerialization.JSONObjectWithData(apidata!, options:[]) as! NSDictionary
let channel = data["channel"] as! NSDictionary
// NSLog("\(data)")
let result = channel["item"] as! NSArray
var book : BookAPIresult
for row in result {
book = BookAPIresult()
let title = row["title"] as? String
let decodedTitle = title?.stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let titleFromHTML = decodedTitle!.html2String
let titleRemoveB = titleFromHTML
let titleRemoveBEnd = titleRemoveB.stringByReplacingOccurrencesOfString("</b>", withString: "")
book.title = titleRemoveBEnd
if let authorEx = row["author"] as? String{
book.author = authorEx
}else{
book.author = ""
}
book.thumbnail = row["cover_s_url"] as? String
//NSLog("\(book.thumbnail)")
let description = row["description"] as? String
let decodedDescription = description?.stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
book.description = decodedDescription!
self.list.append(book)
}
} catch {
NSLog("parse error")
}
}
func getThumbnailImage(index : Int) -> UIImage {
let book = self.list[index]
if let savedImage = book.thumbnailImage {
return savedImage
} else {
if book.thumbnail == "" {
book.thumbnailImage = UIImage(named:
"Book Shelf-48.png")
}else{
let url = NSURL(string: book.thumbnail!)
let imageData = NSData(contentsOfURL: url!)
book.thumbnailImage = UIImage(data:imageData!)
}
return book.thumbnailImage!
}
}
func handleRefresh(refreshControl:UIRefreshControl){
self.searchString = self.searchController.searchBar.text!
self.list.removeAll()
self.callBookAPI()
self.tableView.reloadData()
refreshControl.endRefreshing()
}
// hide keyboard if tapped
func hideKeyboardTap(recognizer: UITapGestureRecognizer) {
self.view.endEditing(true)
}
// hide keyboard if swipe
func hideKeyboardSwipe(recognizer: UISwipeGestureRecognizer) {
self.view.endEditing(true)
}
override func prefersStatusBarHidden() -> Bool {
return false
}
}
extension String {
var html2AttributedString: NSAttributedString? {
guard
let data = dataUsingEncoding(NSUTF8StringEncoding)
else { return nil }
do {
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil)
} catch let error as NSError {
print(error.localizedDescription)
return nil
}
}
var html2String: String {
return html2AttributedString?.string ?? ""
}
}
extension SearchHome: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
// filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
}