Dynamically assign ViewController to Navigate - ios

In my case I have UITableView and have View all button for the listing of all the items in separate screens. So I added target for UIButton action method in cellForRowAt. Now what I am doing in action method:
#IBAction func btnViewAllOffer(_ sender: UIButton) {
let buttonPosition = sender.convert(CGPoint.zero, to: self.tblOfferView)
let indexPath = self.tblOfferView.indexPathForRow(at: buttonPosition)
if indexPath != nil {
if let type = self.homeData[indexPath!.section].type {
if type == HomeDataType.SponserProduct.rawValue {
let vc1 = self.storyboard?.instantiateViewController(withIdentifier: "ViewController1") as! ViewController1
if let title = self.homeData[indexPath!.section].title {
vc1.title = title
}
self.navigationController?.pushViewController(vc1, animated: true)
} else if type == HomeDataType.Offer.rawValue {
let vc2 = self.storyboard?.instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
if let title = self.homeData[indexPath!.section].title {
vc2.title = title
}
self.navigationController?.pushViewController(vc2, animated: true)
} else if type == HomeDataType.BestSeller.rawValue {
let vc3 = self.storyboard?.instantiateViewController(withIdentifier: "ViewController3") as! ViewController3
if let title = self.homeData[indexPath!.section].title {
vc3.title = title
}
self.navigationController?.pushViewController(vc3, animated: true)
}
}
}
}
What I need, is there any way I can minimize the code and assign viewcontrollers dynamically so there is no need to instantiate each view controller and push them everytime?
Something like:
var vc = UIViewController()
if let type = self.homeData[indexPath!.section].type {
if type == HomeDataType.SponserProduct.rawValue {
vc = ViewController1()
}
else if type == HomeDataType.Offer.rawValue {
vc = ViewController2()
} else if type == HomeDataType.BestSeller.rawValue {
vc = ViewController3()
}
}
self.navigationController?.pushViewController(vc, animated: true)

Use a protocol (SimilarViewController) to define the common properties like title:
protocol SimilarViewController {
var title: String? { get set }
}
class ViewController1: UIViewController, SimilarViewController {
var title: String?
}
class ViewController2: UIViewController, SimilarViewController {
var title: String?
}
class ViewController3: UIViewController, SimilarViewController {
var title: String?
}
#IBAction func btnViewAllOffer(_ sender: UIButton) {
let buttonPosition = sender.convert(CGPoint.zero, to: self.tblOfferView)
let indexPath = self.tblOfferView.indexPathForRow(at: buttonPosition)
if indexPath != nil {
if let type = self.homeData[indexPath!.section].type {
var vcGeneric: SimilarViewController?
if type == HomeDataType.SponserProduct.rawValue {
vcGeneric = self.storyboard?.instantiateViewController(withIdentifier: "ViewController1") as! ViewController1
} else if type == HomeDataType.Offer.rawValue {
vcGeneric = self.storyboard?.instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
} else if type == HomeDataType.BestSeller.rawValue {
vcGeneric = self.storyboard?.instantiateViewController(withIdentifier: "ViewController3") as! ViewController3
}
if let title = self.homeData[indexPath!.section].title {
vcGeneric?.title = title
}
if let vcGeneric = vcGeneric as? UIViewController {
self.navigationController?.pushViewController(vcGeneric, animated: true)
}
}
}
}

1: create a struct and assign the value to it.
struct TitleDetails {
static var title : String = ""
}
2: create an extension of viewController and use it to avoid code repetition.
extension UIViewController {
func pushVC(_ vcName : String) {
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: vcname)
self.navigationController?.pushViewController(vc, animated: true)
}
}
3: now you can call it directly as,
TitleDetails.title = yourTitleValue
self.pushVC("ViewController1")
and in your ViewDidLoad() method of your destination view controller,
self.title = TitleDetails.title

Create BaseViewController and derived other ViewController from BaseViewController
class BaseViewController: UIViewController {
var viewTitle = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func pushVC(_ vcName : String) {
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: vcName)
self.navigationController?.pushViewController(vc, animated: true)
}
}
And use below code on ViewController you need like:
#IBAction func btnViewAllOffer(_ sender: UIButton) {
let buttonPosition = sender.convert(CGPoint.zero, to: self.tblOfferView)
let indexPath = self.tblOfferView.indexPathForRow(at: buttonPosition)
if indexPath != nil {
if let type = self.homeData[indexPath!.section].type {
self.viewTitle = self.homeData[indexPath!.section].title
if type == HomeDataType.SponserProduct.rawValue {
self.pushVC("ViewController1")
} else if type == HomeDataType.Offer.rawValue {
self.pushVC("ViewController2")
} else if type == HomeDataType.BestSeller.rawValue {
self.pushVC("ViewController3")
}
}
}
}

Related

Table View is empty when I switch Tab Bar controller screens

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.

Passing data to ConrainerView from ViewControlller always nil

I have CurrentYearViewController in that I used container to show multiple views. The problem is value that I am sending to ContainerViewController is getting always nil
CurrentYearViewController
//calling this function after getting response, not presenting because it is called from Segmented Control
func refreshCurrentYearListView(dict: NSDictionary) {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let containerViewController = mainStoryboard.instantiateViewController(withIdentifier: "containerView") as!
ContainerViewController
containerViewController.dataDictionary = dict
}
ContainerViewController
class ContainerViewController: UIViewController {
#IBOutlet weak var billedValueLbl: UILabel!
var dataDictionary: NSDictionary!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
if let data = dataDictionary {
populateJSON(dict: data)
}
}
func populateJSON(dict: NSDictionary) {
let N_A: String = "N/A"
let parser = CommonParser()
let currentYearSalesSummaryDict: NSDictionary = parser.parse(dictionary: dict, key: "currentYearInvoiceSummary")
if currentYearSalesSummaryDict.count > 0 {
billedValueLbl.text = parser.parse(dictionary: currentYearSalesSummaryDict, key: "totalInvoiceAmount", exceptionString: N_A)
}
}

Label Outlet can not edit by other view Controller in swift 3

i wanted to change the login screen userName Outlet but its not working i can not find our the solution
let loginVC = storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
if self.emailTextField.text == "" {
loginVC.userName?.text = "Hello"
} else {
loginVC.userName?.text = self.emailTextField.text!
}
navigationController?.pushViewController(loginVC, animated: true)
Try this:
let loginVC = storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
if self.emailTextField.text == ""
{
loginVC.str = "Hello"
}
else
{
loginVC.str = self.emailTextField.text!
}
navigationController?.pushViewController(loginVC, animated: true)
LoginViewController
class LoginViewController: UIViewController
{
var str:String! = nil
override func viewDidLoad()
{
super.viewDidLoad()
self.userName.text = str
}
}

How to make UIPageViewController switch controllers automatically

I was following this great tutorial from Duc Tran about UIPageViewController. I was wondering how would you make the controllers inside your UIPageViewController transition automatically without having the user swipe. This is how the code looks without the delegate and datasource.
class AnimesPageVC: UIPageViewController {
override var navigationOrientation: UIPageViewControllerNavigationOrientation {return .horizontal}
weak var pageViewControllerDelegate: AnimePagesVCDelegate?
var timeInterval: Int?
var images: [UIImage]?
lazy var animes: [UIViewController] = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var animes = [UIViewController]()
if let images = self.images {
for image in images {
let anime = storyboard.instantiateViewController(withIdentifier: "AnimeImage")
animes.append(anime)
}
}
self.pageViewControllerDelegate?.setUpPageController(numberOfPages: animes.count)
return animes
}()
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
dataSource = self
loadPage(atIndex: 0)
}
func loadPage(atIndex: Int) {
let anime = animes[atIndex]
var direction = UIPageViewControllerNavigationDirection.forward
if let currentAnime = viewControllers?.first {
if let currentIndex = animes.index(of: currentAnime) {
if currentIndex > atIndex {
direction = .reverse
}
}
}
configurePages(viewController: anime)
setViewControllers([anime], direction: direction, animated: true, completion: nil)
}
func configurePages(viewController: UIViewController) {
for (index, animeVC) in animes.enumerated() {
if viewController === animeVC {
if let anime = viewController as? AnimeVC {
anime.image = self.images?[index]
self.pageViewControllerDelegate?.turnPageController(to: index)
}
}
}
}
}
So how would I be able to get that kind of behavior. Would appreciate any help. :)
Add a timer to your view did load and call the same load function with updated index
Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true) { (_) in
// call your function here
self.loadPage(atIndex: index + 1)
// you have to update your index also.
self.index = self.index + 1
}
This will call your loadPage function each 0.3 sec
keep in mind that my solution is only for one way if you it's only going to next page because I am adding to automatically it will not come back to previous controller for that you have do something like
index = index - 1

Segue value nil in ViewDidLoad but has value in didSet

I am passing a Core Data entity to the next View Controller with a prepareForSegue like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "MemberDetails" {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MemberDetails") as! MemberDetails
let index = self.memberTable.indexPathForSelectedRow
if searchPredicate == nil {
let member = self.sections[index!.section].members[index!.row]
member.printMember()
vc.member = member
} else {
vc.member = self.filteredMembers[index!.row]
}
}
}
And in my receiving View Controller i have this:
var member : Member? {
didSet {
print("")
print(" --------------------- ")
print("")
member?.printMember()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print("")
print(" --------View Did Load -------- ")
print("")
self.member?.printMember()
}
With the following output:
----------_-----------
// member.printMember() function output
--------View Did Load --------
// no ouput -> object is nil
This means that the didSet happens before the viewDidLoad and it has values but for some reason it is emptied again when the viewDidLoad is executed (object = nil)
Why is this happening? / How do i mitigate this effect?
I think you misunderstood what a segue is.
You are instantiating a new MemberDetails on prepareForSegue
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MemberDetails") as! MemberDetails
If the prepareForSegue method is called, this means a viewController from the storyboard is already being loaded
what you need is
if segue.identifier == "MemberDetails" {
if let vc = segue.destinationViewController as? MemberDetails{
let index = self.memberTable.indexPathForSelectedRow
if searchPredicate == nil {
let member = self.sections[index!.section].members[index!.row]
member.printMember()
vc.member = member
} else {
vc.member = self.filteredMembers[index!.row]
}
}
}

Resources