Related
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.
I have an issue.
I get an error below in the code saying: "Cannot convert value type 'Node' to expected argument type 'UIViewController' How to solve this?
the code for the document view controller is below:
import UIKit
import WebKit
import AEXML
import STPopup
import Kanna
import DropDownMenuKit
import Toaster
typealias DocumentOpenAction = (_ node: Node) -> ()
class DocumentViewController: BaseViewController {
var currentNode:Node! {
didSet {
if popupController == nil {
navigationItem.titleView = UILabel.forTitleView(withText: currentNode.title)
if titleView != nil {
navigationItem.titleView = titleView
}
} else {
navigationItem.titleView = UILabel.forTitleView(withText: currentNode.title)
}
}
}
//ausgegebene HTML's
var sections:[[String:String]] = []
var changeMarksVisible:Bool? {
didSet {
self.updateChangeMarking()
}
}
var nightModeOn:Bool? {
didSet {
self.updateNightMode()
}
}
var readAccessFolder:URL?
lazy var statusBarHeight: CGFloat = {
let statusBarSize = UIApplication.shared.statusBarFrame.size
return min(statusBarSize.width, statusBarSize.height)
}()
//
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(DocumentViewController.taskGotDeleted(withNotification:)), name: PackageManager.shared.tasksDeletedNotification, object: nil)
contentSizeInPopup = CGSize(width: 600, height: 500)
landscapeContentSizeInPopup = CGSize(width: 600, height: 500)
changeMarksVisible = UserDefaults.standard.bool(forKey: "ChangeMarkings")
nightModeOn = UserDefaults.standard.bool(forKey: "nightTheme")
if popupController == nil {
PackageManager.shared.setCurrentNodeAndAddToHistory(currentNode)
setupNavBar()
// create the drop down menu
createDropDownMenu()
//
jumpToGraphicsViewButton.addTarget(self, action: #selector(DocumentViewController.showGraphicsView), for: .touchUpInside)
jumpToGraphicsViewButtonLeadingConstraint.constant = 8.0
jumpToGraphicsViewButtonWidthConstraint.constant = 48.0
jumpToGraphicsViewButton.isEnabled = false
jumpToGraphicsViewButton.isHidden = false
} else {
setupNavBarForPreview()
//
jumpToGraphicsViewButton.isHidden = true
jumpToGraphicsViewButtonLeadingConstraint.constant = 0.0
jumpToGraphicsViewButtonWidthConstraint.constant = 0.0
}
// webview
setupWebview()
// process html of current node
splitHTML(forCurrentNode: currentNode)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
PackageManager.shared.currentDisplayedModuleNode = currentNode
navigationBarMenu?.container = view
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (ctx) in
self.show3dModelButtonLeadConstraint?.constant = self.view.frame.width - 50
self.show3dModelButton?.updateConstraintsIfNeeded()
self.webview?.scrollView.updateConstraintsIfNeeded()
// If we put this only in -viewDidLayoutSubviews, menu animation is
// messed up when selecting an item
self.updateMenuContentOffsets()
}) { (ctx) in
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
URLCache.shared.removeAllCachedResponses()
}
deinit {
NotificationCenter.default.removeObserver(self)
webview?.scrollView.delegate = nil
}
func showListOfContent(_ sender: AnyObject) {
_ = navigationController?.popViewController(animated: true)
}
}
// MARK: - UI
extension DocumentViewController {
func setupWebview() {
//Content Controller object
let controller = WKUserContentController()
//Add message handler reference
controller.add(self, name: "shoppingcart")
//Create configuration
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
var f = webViewView.frame
f.origin.y = 0
webview = WKWebView(frame: f, configuration: configuration)
webview?.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
webview?.backgroundColor = .white
webview?.scrollView.bounces = true
webview?.scrollView.delegate = self
webview?.navigationDelegate = self
webview?.uiDelegate = self
webViewView.addSubview(webview!)
webview?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
func setupNavBar() {
//loads nav bar if not presented in popup
settingsButton = UIBarButtonItem(image: UIImage(named: "Settings"), style: .plain, target: self, action: #selector(DocumentViewController.showSettings(_:)))
navigationItem.rightBarButtonItems = [noticeButton,settingsButton]
listOfContentButton = UIBarButtonItem(image: UIImage(named: "List"), style: .plain, target: self, action: #selector(DocumentViewController.showListOfContent(_:)))
shoppingCartButton = UIBarButtonItem(image: UIImage(named: "Checkout"), style: .plain, target: self, action: #selector(DocumentViewController.shoppingCartButtonPressed(_:)))
taskListButton = ZABarButtonItem(image: UIImage(named: "TaskList"), style: .plain, target: self, action: #selector(DocumentViewController.taskListButtonPressed(_:)))
taskListButton.isSelected = PackageManager.shared.nodeIsInTasks(currentNode)
taskListButton.tintColor = taskListButton.isSelected ? navigationController?.navigationBar.tintColor : .lightGray
favoritesButton = ZABarButtonItem(image: UIImage(named: "Star"), style: .plain, target: self, action: #selector(DocumentViewController.favoritesButtonPressed(_:)))
favoritesButton.isSelected = PackageManager.shared.nodeIsInFavorites(currentNode)
let img = favoritesButton.isSelected ? UIImage(named: "StarFilled"): UIImage(named: "Star")
favoritesButton.image = img
backToManualStructure = UIBarButtonItem(image: UIImage(named: "List"), style: .plain, target: self, action: #selector(DocumentViewController.structureButtonPressed(_:)))
var items:[UIBarButtonItem] = [backToManualStructure,shoppingCartButton, favoritesButton]
if currentNode.canBeAddedToTasks() {
items.append(taskListButton)
}
navigationItem.leftBarButtonItems = items
}
func setupNavBarForPreview() {
//loads nav bar if presented in popup
closeButton = UIBarButtonItem(title: NSLocalizedString("Close", tableName: "Localizable", bundle: Bundle.main, value: "", comment: ""), style: .plain, target: self, action: #selector(DocumentViewController.cancel))
navigationItem.leftBarButtonItems = [closeButton]
navigationItem.leftItemsSupplementBackButton = false
openButton = UIBarButtonItem(title: NSLocalizedString("Open in new tab", tableName: "Localizable", bundle: Bundle.main, value: "", comment: ""), style: .plain, target: self, action: #selector(DocumentViewController.openDocument))
navigationItem.rightBarButtonItems = [openButton]
}
}
// MARK: - DropDownMenu
extension DocumentViewController {
func createDropDownMenu() {
// create the drop down menu
let title = prepareNavigationBarMenuTitleView()
prepareNavigationBarMenu(title)
updateMenuContentOffsets()
}
func prepareNavigationBarMenuTitleView() -> String {
// Both title label and image view are fixed horizontally inside title
// view, UIKit is responsible to center title view in the navigation bar.
// We want to ensure the space between title and image remains constant,
// even when title view is moved to remain centered (but never resized).
titleView = DropDownTitleView(frame: CGRect(x: 0, y: 0, width: 150, height: 40))
titleView.addTarget(self,
action: #selector(DocumentViewController.willToggleNavigationBarMenu(_:)),
for: .touchUpInside)
titleView.addTarget(self,
action: #selector(DocumentViewController.didToggleNavigationBarMenu(_:)),
for: .valueChanged)
titleView.titleLabel.textColor = UIColor.black
titleView.title = currentNode.title
navigationItem.titleView = titleView
return titleView.title!
}
func prepareNavigationBarMenu(_ currentChoice: String) {
navigationBarMenu = DropDownMenu(frame: view.bounds)
navigationBarMenu?.delegate = self
var cells:[DropDownMenuCell] = []
for (index, doc) in PackageManager.shared.openNodes.enumerated() {
let cell = DropDownMenuCell()
cell.textLabel!.text = doc.title
cell.tag = index
cell.menuAction = #selector(DocumentViewController.choose(_:))
cell.menuTarget = self
if currentChoice == doc.title {
cell.accessoryType = .checkmark
}
cells.append(cell)
}
navigationBarMenu?.menuCells = cells
// If we set the container to the controller view, the value must be set
// on the hidden content offset (not the visible one)
navigationBarMenu?.visibleContentOffset = (navigationController?.navigationBar.frame.size.height ?? 44.0) + statusBarHeight
// For a simple gray overlay in background
navigationBarMenu?.backgroundView = UIView(frame: view.bounds)
navigationBarMenu?.backgroundView!.backgroundColor = UIColor.black
navigationBarMenu?.backgroundAlpha = 0.7
}
func updateMenuContentOffsets() {
navigationBarMenu?.visibleContentOffset = (navigationController?.navigationBar.frame.size.height ?? 44.0) + statusBarHeight
}
#IBAction func choose(_ sender: AnyObject) {
let cell = (sender as! DropDownMenuCell)
titleView.title = cell.textLabel!.text
let index = cell.tag
let node = PackageManager.shared.openNodes[index]
if node != currentNode {
initalSegment = 0
currentNode = node
setupNavBar()
splitHTML(forCurrentNode: currentNode)
}
if let menu = navigationBarMenu {
didTapInDropDownMenuBackground(menu)
}
}
#IBAction func willToggleNavigationBarMenu(_ sender: DropDownTitleView) {
sender.isUp ? navigationBarMenu?.hide() : navigationBarMenu?.show()
}
#IBAction func didToggleNavigationBarMenu(_ sender: DropDownTitleView) {
}
}
// MARK: - DropDownMenuDelegate
extension DocumentViewController : DropDownMenuDelegate {
func didTapInDropDownMenuBackground(_ menu: DropDownMenu) {
if menu == navigationBarMenu {
titleView.toggleMenu()
}
else {
menu.hide()
}
}
}
// MARK: - data module
extension DocumentViewController {
func splitHTML(forCurrentNode node:Node) {
node.deleteTemporaryHtmls()
if let nodePath = node.path {
let pathComponents = URL(fileURLWithPath: nodePath).pathComponents
if pathComponents.count >= 2 {
let rootFolder = "\(pathComponents[1])"
readAccessFolder = URL(fileURLWithPath: "\(PackageManager.shared.packageFolder)\(rootFolder)")
}
}
// segmented control
segmentedControl.removeAllSegments()
// process html of current node
do {
sections = try node.processHTMLSections()
if sections.count > 0 {
var index = 0
for sec in sections {
segmentedControl.insertSegment(withTitle: sec["title"], at: index, animated: false)
index += 1
}
//
let hasWCN = sections.first(where: { (sec) -> Bool in
return sec["contenttype"] == "safety"
})
if let _ = hasWCN {
} else {
let index = sections.index(where: { (sec) -> Bool in
return sec["contenttype"] == "container"
})
if let i = index {
initalSegment = i
}
}
//
if initalSegment > 5 {
initalSegment = 0
loadHTML(forSection: initalSegment)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
self.show3DModel(self.show3dModelButton as Any)
})
}
else {
if initalSegment > sections.count {
initalSegment = 0
}
loadHTML(forSection: initalSegment)
}
segmentedControl.selectedSegmentIndex = initalSegment
// configure show 3d model button
let button = UIButton(forAutoLayout: ())
button.imageView?.contentMode = .scaleAspectFit
button.imageView?.tintColor = .gray
button.setImage(UIImage(named: "Next"), for: .normal)
button.backgroundColor = UIColor.lightGray.withAlphaComponent(0.3)
button.borderColor = .black
button.borderWidth = 1.0
button.addTarget(self, action: #selector(DocumentViewController.show3DModel(_:)), for: .touchUpInside)
webViewView.addSubview(button)
button.autoAlignAxis(.horizontal, toSameAxisOf: webViewView)
button.autoSetDimension(.height, toSize: 150.0)
button.autoSetDimension(.width, toSize: 50.0)
show3dModelButtonLeadConstraint = button.autoPinEdge(.trailing, to: .trailing, of: webViewView, withOffset: 0)
show3dModelButton = button
// we dont need the button any longer
show3dModelButton?.isHidden = true
}
} catch {
loadPDF()
segmentedControlHeight.constant = 0
segmentedControlMarginTop.constant = 0
segmentedControlMarginBottom.constant = 0
}
if let dmc = node.moduleCode {
dmcLabel.text = dmc
}
if let issno = node.issueNumber {
issnoLabel.text = issno
}
if let issdate = node.issueDate {
issdateLabel.text = DateFormatter.stringFromDate(issdate, format: "yyyy-MM-dd")
}
let edgePan = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(returnToGraphicView))
edgePan.edges = .right
view.addGestureRecognizer(edgePan)
}
func loadHTML(forSection section: Int) {
URLCache.shared.removeAllCachedResponses()
URLCache.shared.diskCapacity = 0
URLCache.shared.memoryCapacity = 0
if section > sections.count {
return
}
if webview?.isLoading == true {
webview?.stopLoading()
}
if let urlString = sections[section]["url"], let contenttype = sections[section]["contenttype"], let readAccessFolder = readAccessFolder {
var url = URL(fileURLWithPath: urlString)
if var components = URLComponents(url: url, resolvingAgainstBaseURL: false), contenttype == "requirements" {
let sc = URLQueryItem(name: "shoppingcart", value: "true")
let domain = URLQueryItem(name: "domain", value: "*")
components.queryItems = [sc, domain]
if let newUrl = components.url {
url = newUrl
}
}
_ = webview?.loadFileURL(url, allowingReadAccessTo: readAccessFolder)
}
}
func loadPDF() {
URLCache.shared.removeAllCachedResponses()
URLCache.shared.diskCapacity = 0
URLCache.shared.memoryCapacity = 0
if webview?.isLoading == true {
webview?.stopLoading()
}
let fileStr = "\(PackageManager.shared.packageFolder)\(currentNode.path ?? "")"
let url = URL(fileURLWithPath: fileStr)
let request = URLRequest(url: url)
if let readAccessFolder = readAccessFolder {
_ = webview?.loadFileURL(url, allowingReadAccessTo: readAccessFolder)
} else {
_ = webview?.load(request)
}
}
}
// MARK: - Illustrations
extension DocumentViewController {
func showFullscreenFigure(with boardNo: String, and components: URLComponents?) {
if let gv = self.storyboard?.instantiateViewController(withIdentifier: "GraphicsViewController") as? GraphicsViewController {
gv.url = URL(fileURLWithPath: "\(PackageManager.shared.packageFolder)\(currentNode.path ?? "").\(boardNo).$tmp.htm")
gv.caption = components?.queryItems?.filter({ (item) in item.name == "caption"}).first?.value
gv.javascript = components?.queryItems?.filter({ (item) in item.name == "javascript"}).first?.value
gv.readAccessFolder = readAccessFolder
graphicsView = gv
}
if popupController != nil {
popupController?.push(graphicsView!, animated: true)
} else {
navigationController?.pushViewController(graphicsView!, animated: true)
}
}
func showGraphicsView() {
if let graphicsView = graphicsView {
if popupController != nil {
popupController?.push(graphicsView, animated: true)
} else {
navigationController?.pushViewController(graphicsView, animated: true)
}
}
}
func returnToGraphicView(_ recognizer: UIScreenEdgePanGestureRecognizer) {
if recognizer.state == .recognized {
showGraphicsView()
}
}
}
// MARK: - Preview
extension DocumentViewController {
func cancel() {
onClose?()
}
func openDocument() {
onOpen?(currentNode)
}
func showPreview(for node:Node) {
let onOpen:DocumentOpenAction = { node in
self.currentNode = node
PackageManager.shared.setCurrentNodeAndAddToHistory(self.currentNode)
self.initalSegment = 0
self.splitHTML(forCurrentNode: self.currentNode)
self.createDropDownMenu()
}
let contentView = self.storyboard?.instantiateViewController(withIdentifier: "DocumentViewController") as! DocumentViewController
contentView.initalSegment = 0
contentView.currentNode = node
//
if popupController != nil {
contentView.onOpen = self.onOpen
contentView.onClose = self.onClose
self.popupController?.push(contentView, animated: true)
} else {
let popup = STPopupController(rootViewController: contentView)
popup.style = .formSheet
popup.hidesCloseButton = false
popup.backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
popup.containerView.layer.cornerRadius = 4
contentView.onOpen = { node in
popup.dismiss(completion: {
onOpen(node)
})
}
contentView.onClose = {
popup.dismiss(completion: {
// we dont need to split the html again for now
// self.splitHTML(forCurrentNode: self.currentNode)
})
}
popup.present(in: self, completion: nil)
}
contentView.navigationItem.titleView = UILabel.forTitleView(withText: node.title)
}
func showProcedureStepCheckboxes() {
if popupController == nil {
self.webview?.evaluateJavaScript("showProcedureStepCheckboxes()", completionHandler: {(result, error) in
guard let err = error else {return}
print(err)
})
}
}
func setLastScrollingPosition() {
if let code = currentNode.contentobjectcode {
webview?.restoreContentOffset(forKey: code)
}
}
}
// MARK: - Settings
extension DocumentViewController {
func showSettings(_ sender: AnyObject) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SetSettingsViewController") as! SetSettingsViewController
vc.modalPresentationStyle = .popover
vc.onChange = {
self.changeMarksVisible = (UserDefaults.standard.bool(forKey: "ChangeMarkings"))
self.nightModeOn = (UserDefaults.standard.bool(forKey: "nightTheme"))
}
if let popover = vc.popoverPresentationController {
popover.barButtonItem = settingsButton
popover.permittedArrowDirections = .any
}
present(vc, animated: true, completion: nil)
}
func updateChangeMarking() {
if (self.changeMarksVisible ?? false) {
self.webview?.evaluateJavaScript("handleChangemarks()", completionHandler: {(result, error) in
})
}
else {
self.webview?.evaluateJavaScript("deleteChangemarks()", completionHandler: {(result, error) in
})
}
}
func updateNightMode() {
let mode = self.nightModeOn ?? false
self.webview?.evaluateJavaScript("s1000d.setNightMode(\(mode))", completionHandler: {(result, error) in
})
}
}
// Mark: - Structure Manual
extension DocumentViewController {
func structureButtonPressed(_ sender: AnyObject) {
PackageManager.shared.structureButtonPressed(currentNode)
if let root = self.parent?.parent as? RootTabBarViewController {
root.selectedIndex = 0
if let navController = root.viewControllers?.first as? UINavigationController, let firstController = navController.viewControllers.first as? ManualsViewController {
PackageManager.shared.strucutreArrayNode.removeLast()
for var i in PackageManager.shared.strucutreArrayNode {
print("\(i.title)")
// get next child node
if let next = i.nextChild() {
i = next
}
if i.type == "document" || i.subnodes.count == 0 {
firstController.showDocumentViewController(for: i)
} else {
firstController.navigationController?.pushViewController(i, animated: false)
}
}
}
}
}
}
I have a form in which I am displaying User existing data in Textfield and there is a profile image upload option as well. So lets say If I edit some fields in the textbox and then upload image from using imagePicker, then the data resets and it shows the old values. I don't know how can I fix this
My Code is this :-
class ProfileVC: UIViewController, TopViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UITextFieldDelegate {
#IBOutlet weak var topView: WATopView!
#IBOutlet weak var firstName: WATextField!
#IBOutlet weak var lastName: WATextField!
#IBOutlet weak var email: WATextField!
// #IBOutlet weak var password: WATextField!
#IBOutlet weak var university: WATextField!
#IBOutlet weak var graduationDate: WATextField!
#IBOutlet weak var major: WATextField!
#IBOutlet weak var homeTown: WATextField!
#IBOutlet weak var industry: WATextField!
#IBOutlet var profileImageView: WAImageView!
#IBOutlet weak var imagePickerButton:WAButton!
var pickerView = UIPickerView()
var uniList = [University]()
var industryList = [Industry]()
var selectedIndustry: Industry?
var selectedUni: University?
let imagePicker = UIImagePickerController()
var base64StringOf_my_image = String()
var prepCompressedImage: UIImage!
var isDismissing: Bool = false
let currentUser = User.getCurrentUser()
var inputViews = UIView()
let datePickerView = UIDatePicker()
let profileLoader = ProfileLoader()
override func viewDidLoad() {
super.viewDidLoad()
if fireNotification.pickedImage != nil {
profileImageView.image = fireNotification.pickedImage!.circle
self.prepCompressedImage = UIImage.compressImage(fireNotification.pickedImage, compressRatio: 0.9)
base64StringOf_my_image = appUtility.base64StringOfImage(self.prepCompressedImage)
fireNotification.pickedImage = nil
}else {
profileImageView.sd_setImageWithURL(NSURL(string: currentUser!.userImageURL), placeholderImage: UIImage(named:"no-image"))
self.prepCompressedImage = UIImage.compressImage(profileImageView.image, compressRatio: 0.9)
base64StringOf_my_image = appUtility.base64StringOfImage(self.prepCompressedImage)
}
pickerView.delegate = self
pickerView.dataSource = self
loadIndAndUni()
topView.delegate = self
disableEditing(false)
if !(currentUser?.firstName.isEmpty)! {
firstName.text = currentUser?.firstName
}
if !(currentUser?.lastName.isEmpty)! {
lastName.text = currentUser?.lastName
}
if !(currentUser?.email.isEmpty)! {
email.text = currentUser?.email
}
if !(currentUser?.uni_name.isEmpty)! {
university.text = currentUser?.uni_name
}
if !(currentUser?.startGradDate.isEmpty)! {
graduationDate.text = currentUser?.startGradDate
}
if !(currentUser?.major.isEmpty)! {
major.text = currentUser?.major
}
if !(currentUser?.homeTown.isEmpty)! {
homeTown.text = currentUser?.homeTown
}
if !(currentUser?.ind_name.isEmpty)! {
industry.text = currentUser?.ind_name
}
imagePickerButton.userInteractionEnabled = false
}
func loadIndAndUni(){
if fireNotification.uniList != nil {
uniList = fireNotification.uniList!
}else { self.loadUni()}
if fireNotification.indList != nil {
industryList = fireNotification.indList!
}else {self.loadIndustries()}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func editDoneButtonAction(sender: UIButton) {
if sender.titleLabel?.text == "Edit" {
topView.doneText = "Done"
// PrepUtility.showAlertWithTitle("Edit", error: "You are going to submit data", OKButton: "Edit", VC: self)
imagePickerButton.userInteractionEnabled = true
disableEditing(true)
}
if sender.titleLabel?.text == "Done" {
// PrepUtility.showAlertWithTitle("Done", error: "You are going to submit data", OKButton: "Done", VC: self)
submitRequest()
topView.doneText = "Edit"
disableEditing(false)
}
}
func submitRequest(){
let (isValid , error) = validateFields()
if !isValid {
appUtility.showAlert(error!,VC: self)
return
}
if (base64StringOf_my_image.isEmpty) {
appUtility.showAlert("Please Select Image",VC: self)
return
}
if PrepUtility.connectedToNetwork() {
appUtility.loadingView(self, isHide: false)
if selectedUni != nil {
let indText = industry.text
var selectedI: Industry?
for t in industryList {
if t.ind_name == indText {
selectedI = t
}
}
let params = ["std_id":currentUser!.std_id,"std_f_name":firstName.text!,"std_l_name":lastName.text!,"std_grad_date":graduationDate.text!,"std_hometown":homeTown.text!,"std_major":major.text!,"uni_id":selectedUni!.uni_id,"std_img":["content_type": "image/png", "filename":"test.png", "file_data": base64StringOf_my_image],"ind_id":selectedI!.ind_id]
editProfile(params)
}else {
let uniText = university.text
var selectedU: University?
for t in uniList {
if t.uni_name == uniText {
selectedU = t
}
}
let indText = industry.text
var selectedI: Industry?
for t in industryList {
if t.ind_name == indText {
selectedI = t
}
}
if selectedU!.uni_id.boolValue {
let params = ["std_id":currentUser!.std_id,"std_f_name":firstName.text!,"std_l_name":lastName.text!,"std_grad_date":graduationDate.text!,"std_hometown":homeTown.text!,"std_major":major.text!,"uni_id":selectedU!.uni_id,"std_img":["content_type": "image/png", "filename":"test.png", "file_data": base64StringOf_my_image],"ind_id":selectedI!.ind_id]
editProfile(params)
}
}
}else {
appUtility.loadingView(self, isHide: true)
appUtility.showNoNetworkAlert()
}
}
func editProfile(params:[String:AnyObject]) {
profileLoader.tryStudentProfileEdit(params, successBlock: { (user) in
appUtility.loadingView(self, isHide: true)
}, failureBlock: { (error) in
// appUtility.showAlert((error?.userInfo["NSLocalizedDescription"])! as! String, VC: self)
if let err = error?.userInfo["NSLocalizedDescription"] {
appUtility.showAlert(err as! String, VC: self)
appUtility.loadingView(self, isHide: true)
}else {
appUtility.loadingView(self, isHide: true)
appUtility.showAlert("Something went wrong", VC: self)
}
})
}
func openMenu() {
firstName.resignFirstResponder()
lastName.resignFirstResponder()
// email.resignFirstResponder()
// password.resignFirstResponder()
university.resignFirstResponder()
graduationDate.resignFirstResponder()
major.resignFirstResponder()
homeTown.resignFirstResponder()
industry.resignFirstResponder()
self.mainSlideMenu().openLeftMenu()
}
//MARK:- Private Methods
private func validateFields() -> (Bool , String?) {
if !firstName.isValid() {
hideView()
return (false , "Please enter your First Name")
}
if !lastName.isValid() {
hideView()
return (false , "Please enter your Last Name")
}
// if !email.isValid() {
// hideView()
// return (false , "Please enter email")
// }
//
// if email.isValid() {
// hideView()
// let text = email.text
// if !(text!.hasSuffix(".edu")) {
// return (false , "Please enter email that having .edu")
// }
// if !email.text!.isValidEmail() {
// return (false , "Please Enter a valid email...")
// }
// }
if !university.isValid() {
hideView()
// return (false , "Please select University")
}
if !homeTown.isValid() {
hideView()
// return (false , "Please enter address")
}
// if !password.isValid() {
// return (false , "Please enter password")
// }
//
return (true , nil)
}
private func showGradDatePicker() {
//Create the view
graduationDate.inputView = inputViews
inputViews = UIView(frame: CGRectMake(0, self.view.frame.height, self.view.frame.width, 240))
inputViews.backgroundColor = UIColor.whiteColor()
let datePickerView : UIDatePicker = UIDatePicker(frame: CGRectMake(0, 40, 0, 0))
datePickerView.datePickerMode = UIDatePickerMode.Date
inputViews.addSubview(datePickerView) // add date picker to UIView
let doneButton = UIButton(frame: CGRectMake((self.view.frame.size.width/2) - (100/2), 0, 100, 50))
doneButton.setTitle("Done", forState: UIControlState.Normal)
doneButton.setTitle("Done", forState: UIControlState.Highlighted)
doneButton.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
doneButton.setTitleColor(UIColor.grayColor(), forState: UIControlState.Highlighted)
inputViews.addSubview(doneButton) // add Button to UIView
doneButton.addTarget(self, action: #selector(ScheduleVC.doneButton(_:)), forControlEvents: UIControlEvents.TouchUpInside) // set button click event
// sender.inputView = inputView
datePickerView.addTarget(self, action: #selector(ScheduleVC.datePickerValueChanged(_:)), forControlEvents: UIControlEvents.ValueChanged)
self.view.addSubview(inputViews)
datePickerValueChanged(datePickerView) // Set the date on start.
UIView.animateWithDuration(0.5) {
self.inputViews.frame = CGRect(x: 0, y: self.view.frame.height - 270, width: self.view.frame.width, height: 240)
}
}
func doneButton(sender:UIButton) {
hideView()
}
func hideView() {
UIView.animateWithDuration(0.9) {
self.inputViews.frame = CGRect(x: 0, y:0, width: self.view.frame.width, height: 240)
self.inputViews.removeFromSuperview()
}
}
func datePickerValueChanged(sender:UIDatePicker) {
// isDateSet = true
let dateFormatter = NSDateFormatter()
// dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateFormatter.dateFormat = "yyyy-MM-dd"
// dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
graduationDate.text = dateFormatter.stringFromDate(sender.date)
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
if textField == university {
self.resignFirstResponder(university)
industry.tag = 1
university.tag = 0
graduationDate.tag = 1
pickerViewToolBar(textField)
}
if textField == industry {
self.resignFirstResponder(industry)
industry.tag = 0
university.tag = 1
graduationDate.tag = 1
pickerViewToolBar(textField)
}
if textField == graduationDate{
industry.tag = 1
university.tag = 1
graduationDate.tag = 0
self.resignFirstResponder(graduationDate)
showGradDatePicker()
}
return true
}
private func disableEditing(boo: Bool) {
firstName.enabled = boo
lastName.enabled = boo
// email.enabled = boo
// password.enabled = boo
university.enabled = boo
graduationDate.enabled = boo
major.enabled = boo
homeTown.enabled = boo
industry.enabled = boo
}
private func resignFirstResponder(textField:UITextField) {
if textField != firstName {
// hideView()
textField.resignFirstResponder()
}
if textField != lastName {
// hideView()
textField.resignFirstResponder()
}
// if textField != email{
//// hideView()
// textField.resignFirstResponder()
// }
// if textField != password {
//// hideView()
// textField.resignFirstResponder()
// }
if textField != university {
// hideView()
textField.resignFirstResponder()
}
if textField != graduationDate {
textField.resignFirstResponder()
}
if textField != major {
// hideView()
textField.resignFirstResponder()
}
if textField != homeTown {
// hideView()
textField.resignFirstResponder()
}
if textField != industry {
// hideView()
textField.resignFirstResponder()
}
}
private func resignAllTextFields() {
firstName.resignFirstResponder()
}
//MARK:- Public Methods
func pickerViewToolBar(sender: UITextField) {
var doneButton:UIBarButtonItem?
if university.tag == 0 {
university.inputView = pickerView
}
if industry.tag == 0 {
industry.inputView = pickerView
}
if graduationDate.tag == 0 {
graduationDate.inputView = pickerView
}
// departureDatePickerView.datePickerMode = UIDatePickerMode.Date
// Sets up the "button"
// Creates the toolbar
let toolBar = UIToolbar()
toolBar.barStyle = .Default
toolBar.translucent = true
toolBar.tintColor = UIColor(red: 92/255, green: 216/255, blue: 255/255, alpha: 1)
toolBar.sizeToFit()
// Adds the buttons
if(sender.tag == 0){
// self.nextButton?.hidden = true
doneButton = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(PrepInfoVC.doneClick(_:)))
doneButton!.tag = 0
}
// else if(sender.tag == 2){
//// self.nextButton?.hidden = true
// doneButton = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(PrepInfoVC.doneClick(_:)))
// doneButton!.tag = 2
// }
let spaceButton = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .Plain, target: self, action: #selector(PrepInfoVC.cancelClick))
toolBar.setItems([cancelButton, spaceButton, doneButton!], animated: false)
toolBar.userInteractionEnabled = true
// Adds the toolbar to the view
if university.tag == 0 {
university.inputAccessoryView = toolBar
}
if industry.tag == 0 {
industry.inputAccessoryView = toolBar
}
if graduationDate.tag == 0 {
graduationDate.inputAccessoryView = toolBar
}
}
func doneClick(sender:UIBarButtonItem) {
if industry.tag == 0 {
selectedIndustry = industryList[pickerView.selectedRowInComponent(0)]
industry.text = selectedIndustry!.ind_name
industry.tag = 1
industry.resignFirstResponder()
}else{
selectedUni = uniList[pickerView.selectedRowInComponent(0)]
university.text = selectedUni!.uni_name
university.tag = 1
university.resignFirstResponder()
}
}
func cancelClick() {
if industry.tag == 0 {
industry.tag = 1
industry.resignFirstResponder()
}else {
university.tag = 1
university.resignFirstResponder()
}
}
//MARK:- ImagePicker
#IBAction func loadImageButtonTapped(sender: UIButton) {
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
imagePicker.allowsEditing = true
imagePicker.delegate = self
self.hidesBottomBarWhenPushed = true
self.navigationController?.presentViewController(imagePicker, animated: true, completion: nil)
self.hidesBottomBarWhenPushed = false
}
// MARK: - UIImagePickerControllerDelegate Methods
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
print(info)
if let pickedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
profileImageView.image = pickedImage.circle
self.prepCompressedImage = UIImage.compressImage(pickedImage, compressRatio: 0.9)
base64StringOf_my_image = appUtility.base64StringOfImage(self.prepCompressedImage)
// self.viewWillAppear(false)
fireNotification.pickedImage = pickedImage
isDismissing = true
}else{}
imagePicker.delegate = nil
self.dismissViewControllerAnimated(true,completion: nil)
isDismissing = true
}
}
extension ProfileVC: UIPickerViewDelegate,UIPickerViewDataSource {
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
if university.tag == 0 {
return 1
}else {
return 1
}
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if university.tag == 0 {
return uniList.count
}
else {
return industryList.count
}
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if university.tag == 0 {
let uni = uniList[row]
return String(uni.uni_name)
}else {
let ind = industryList[row]
return String(ind.ind_name)
}
}
}
//MARK:- SearchVC
extension ProfileVC {
func loadUni() {
let userLoader = UserLoader()
let params = ["":""]
if PrepUtility.connectedToNetwork() {
userLoader.tryUniversity(params, successBlock: { (university) in
self.uniList = university!
}) { (error) in
if let err = error?.userInfo["NSLocalizedDescription"] {
appUtility.showAlert(err as! String, VC: self)
}else {
appUtility.showAlert("Something went wrong", VC: self)
}
}
}else {
appUtility.showNoNetworkAlert()
}
}
func loadIndustries() {
let userLoader = UserLoader()
if PrepUtility.connectedToNetwork() {
userLoader.tryIndustry(["":""], successBlock: { (industry) in
self.industryList = industry!
}) { (error) in
if let err = error?.userInfo["NSLocalizedDescription"] {
appUtility.showAlert(err as! String, VC: self)
}else {
appUtility.showAlert("Something went wrong", VC: self)
}
}
}else {
appUtility.showNoNetworkAlert()
}
}
}
Since you don't initialize your UI in a viewWillLoad or similar method, I would say that your issue is coming from your device trying to get some more space.
You are probably out of memory and the system kill what it can (in your case your previous controller).
When you dismiss the image picker, your controller is reloading its views (with your initial values)
i personally would save the .text of the label into variables previously declared (you are going to need them anyway) and in the viewDidAppear method assign the variables values to the textField.Text, when the view appear the first time they will appear empty, when you call the image picker you save the new values and then when the original view appears again it will assing the values you saved before.
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)
}
}
Hi whenever i enter the wrong login information details which is checked at the Firebase database, i want to display an alert controller to stop it from entering the app. But i get an error saying the alertviewcontroller is not the window hierarchy. I don't get that error when i'm calling the function outside of the firebase data block. Could someone explain how to fix this issue?
{
import UIKit
import Firebase
class LoginViewController: UIViewController {
let BASE_REF = Firebase(url: "https://cal-sap.firebaseio.com/?page=Auth")
let USER_REF = Firebase(url: "https://cal-sap.firebaseio.com/?page=Auth/users")
let gradientLayer = CAGradientLayer()
#IBOutlet weak var Email: UITextField!
#IBOutlet weak var Password: UITextField!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
/*let defaults = NSUserDefaults.standardUserDefaults()
let name = defaults.stringArrayForKey("uid")
if name != nil && USER_REF.authData.uid != nil {
self.performSegueWithIdentifier("LoggedinView", sender: self)
print(name);
}
*/
if NSUserDefaults.standardUserDefaults().valueForKey("uid") != nil && DataService.dataService.CURRENT_USER_REF.authData != nil {
self.performSegueWithIdentifier("LoggedinView", sender: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.grayColor()
gradientLayer.frame = self.view.bounds
let color1 = UIColor(red: (69/255.0), green: (69/255.0), blue:(69/255.0), alpha: 0.05).CGColor as CGColorRef
let color2 = UIColor(red: (71/255.0), green: (71/255.0), blue:(71/255.0), alpha: 0.05).CGColor as CGColorRef
let color3 = UIColor(red: (200/255.0), green: (200/255.0), blue:(200/255.0), alpha: 0.05).CGColor as CGColorRef
let color4 = UIColor.whiteColor().CGColor as CGColorRef
gradientLayer.colors = [color1,color2,color3,color4]
gradientLayer.locations = [0.0,0.25,0.75,1.0]
self.view.layer.addSublayer(gradientLayer)
let userimageView = UIImageView();
let userimage = UIImage(named: "Email.png");
userimageView.image = userimage;
Email.leftView = userimageView
Email.leftViewMode = UITextFieldViewMode.Always
userimageView.frame = CGRectMake(20, 10, 15, 20)
let passimageView = UIImageView();
let passimage = UIImage(named: "lock.png");
passimageView.image = passimage;
Password.leftView = passimageView
Password.leftViewMode = UITextFieldViewMode.Always
passimageView.frame = CGRectMake(15, 10, 15, 20)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func LoginButtonTapped(sender: AnyObject) {
if(Email != "" || Password != ""){
/*USER_REF.authUser(Email.text, password:Password.text) {
error, authData in
if error != nil {
self.displayAlertMessage("Information not valid. Please enter again.");
print("user not defined");
} else {
NSUserDefaults.standardUserDefaults().setValue(authData.uid, forKey: "uid")
}
}
*/
DataService.dataService.BASE_REF.authUser(Email.text, password: Password.text, withCompletionBlock: { error, authData in
if error != nil {
print(error)
self.displayAlertMessage("Information invalid. Please enter again.")
} else {
// Be sure the correct uid is stored.
NSUserDefaults.standardUserDefaults().setValue(authData.uid, forKey: "uid")
// Enter the app!
self.performSegueWithIdentifier("CurrentlyLoggedIn", sender: nil)
}
})
}
else{
self.displayAlertMessage("Please fill all the fields")
}
}
func displayAlertMessage(usermessage: String)
{
let MyAlert = UIAlertController(title: "Alert", message: usermessage, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil)
MyAlert.addAction(okAction)
self.presentViewController(MyAlert, animated: true, completion: nil)
}
}
}
#DataService.swift File
{
import Foundation
import Firebase
class DataService {
static let dataService = DataService()
private var _BASE_REF = Firebase(url: "https://cal-sap.firebaseio.com/?page=Auth")
private var _USER_REF = Firebase(url: "https://cal-sap.firebaseio.com/?page=Auth/users")
private var _EVENT_REF = Firebase(url: "https://cal-sap.firebaseio.com/?page=Auth/users/events")
var BASE_REF: Firebase {
return _BASE_REF
}
var USER_REF: Firebase {
return _USER_REF
}
var CURRENT_USER_REF: Firebase {
let userID = NSUserDefaults.standardUserDefaults().valueForKey("uid") as! String
let currentUser = Firebase(url: "\(BASE_REF)").childByAppendingPath("users").childByAppendingPath(userID)
return currentUser!
}
var EVENT_REF: Firebase {
return _EVENT_REF
}
}
}
If you have to deal with UI elements from an async block you have to do it in the main queue:
dispatch_async(dispatch_get_main_queue(), { [weak self] () -> Void in
self?.presentViewController(MyAlert, animated: true, completion: nil)
})
I think this will solve your problem, but for alerts I always use these utility vars:
public var APP_KEY_WINDOW: UIWindow? { get { return UIApplication.sharedApplication().keyWindow } }
public var APP_ROOT_VC: UIViewController? {
get {
guard let root = APP_KEY_WINDOW?.rootViewController else { return nil }
guard root.isViewLoaded() && root.view.window != nil else {
guard let presentedVC = root.presentedViewController else { return nil }
return presentedVC
}
return root
}
}
as follow:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
APP_ROOT_VC?.presentViewController(MyAlert, animated: true, completion: nil)
})