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

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
}
}

Related

Dynamically assign ViewController to Navigate

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")
}
}
}
}

Not able to display tab bar icons in required order

I wanted to display 6 icons on a tab bar in a specific order. For that in the storyboard I have dragged a tab-controller and added 6 viewcontrollers to it. I also added an image to each of the tab bars and also made different viewcontrollers for each of the tab bars.
But the issue is the images/viewcontrollers aren't displaying as per the order specified in the storyboard.
I have a .swift file also for the tabbarcontroller. It has some code for configuring the tab bars given like so...
class SampleTabBarController: UITabBarController, UIGestureRecognizerDelegate {
// MARK: - Shared Instance
static var shared: SampleTabBarController?
// MARK: - Public Properties
var homeTitle = "Home"
var connectionsTitle = "Connections"
var flightTitle = "Flights"
var messagesTitle = "Messages"
var companyProfileTitle = "Company Profile"
var myCalendarTitle = "My Calendar"
// MARK: - Private Properties
fileprivate var homeNavigation = "HomeNavigation"
fileprivate var home: HomeViewController? = nil
fileprivate var homeIndex = 0
fileprivate var connectionsNavigation = "ConnectionsNavigation"
fileprivate var connections: ConnectionsViewController? = nil
fileprivate var connectionsIndex = 1
fileprivate var flightsNavigation = "FlightsNavigation"
fileprivate var flights: FlightsViewController? = nil
fileprivate var flightsIndex = 2
fileprivate var messagesNavigation = "MessagesNavigation"
fileprivate var messages: MessagesViewController? = nil
fileprivate var messagesIndex = 3
fileprivate var companyProfileNavigation = "CompanyProfileNavigation"
fileprivate var compProfile: CompanyProfileViewController? = nil
fileprivate var compProfileIndex = 4
fileprivate var myCalendarNavigation = "MyCalendarNavigation"
fileprivate var myCalendar: MyCalendarViewController? = nil
fileprivate var myCalendarIndex = 5
fileprivate var previousIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
SampleTabBarController.shared = self
initialConfiguration()
}
}
extension SampleTabBarController {
private func initialConfiguration() {
self.tabBarController(SampleTabBarController.shared!,
didEndCustomizing: SampleTabBarController.shared!.viewControllers!,
changed: true)
configureViewControllers()
}
fileprivate func configureViewControllers() {
// Home
if let viewControllers = self.viewControllers {
let navigationControllers = viewControllers.filter { $0.restorationIdentifier == homeNavigation }
if let navigation = navigationControllers.first as? UINavigationController ,
let homeView = navigation.viewControllers[0] as? HomeViewController {
self.home = homeView
}
}
// Connections
if let viewControllers = self.viewControllers {
let navigationControllers = viewControllers.filter { $0.restorationIdentifier == connectionsNavigation }
if let navigation = navigationControllers.first as? UINavigationController ,
let connectionView = navigation.viewControllers[0] as? ConnectionsViewController {
self.connections = connectionView
}
}
// Flight
if let viewControllers = self.viewControllers {
let navigationControllers = viewControllers.filter { $0.restorationIdentifier == flightsNavigation }
if let navigation = navigationControllers.first as? UINavigationController ,
let flightView = navigation.viewControllers[0] as? FlightsViewController {
self.flights = flightView
}
}
// Messages
if let viewControllers = self.viewControllers {
let navigationControllers = viewControllers.filter { $0.restorationIdentifier == messagesNavigation }
if let navigation = navigationControllers.first as? UINavigationController ,
let messagesView = navigation.viewControllers[0] as? MessagesViewController {
self.messages = messagesView
}
}
// Company Profile
if let viewControllers = self.viewControllers {
let navigationControllers = viewControllers.filter { $0.restorationIdentifier == companyProfileNavigation }
if let navigation = navigationControllers.first as? UINavigationController ,
let companyProfileView = navigation.viewControllers[0] as? CompanyProfileViewController {
self.compProfile = companyProfileView
}
}
// My Calendar
if let viewControllers = self.viewControllers {
let navigationControllers = viewControllers.filter { $0.restorationIdentifier == myCalendarNavigation }
if let navigation = navigationControllers.first as? UINavigationController ,
let calendarView = navigation.viewControllers[0] as? MyCalendarViewController {
self.myCalendar = calendarView
}
}
}
}
// MARK: - UITabBarControllerDelegate
extension SampleTabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if previousIndex != tabBarController.selectedIndex {
previousIndex = tabBarController.selectedIndex
var elementText = ""
var elementValue = ""
switch previousIndex {
case homeIndex:
elementText = homeTitle
elementValue = BottomBarItems.home.rawValue
case connectionsIndex:
elementText = connectionsTitle
elementValue = BottomBarItems.connections.rawValue
case flightsIndex:
elementText = flightTitle
elementValue = BottomBarItems.flight.rawValue
case messagesIndex:
elementText = messagesTitle
elementValue = BottomBarItems.messages.rawValue
case compProfileIndex:
elementText = companyProfileTitle
elementValue = BottomBarItems.companyProfile.rawValue
case myCalendarIndex:
elementText = myCalendarTitle
elementValue = BottomBarItems.myCalendar.rawValue
default:
break
}
}
}
func tabBarController(_ tabBarController: UITabBarController, didEndCustomizing viewControllers: [UIViewController], changed: Bool) {
for (index, viewcontroller) in viewControllers.enumerated() {
// Home
if viewcontroller.restorationIdentifier == homeNavigation {
homeIndex = index
}
// Connections
if viewcontroller.restorationIdentifier == connectionsNavigation {
connectionsIndex = index
}
// Flight
if viewcontroller.restorationIdentifier == flightsNavigation {
flightsIndex = index
}
// Messages
if viewcontroller.restorationIdentifier == messagesNavigation {
messagesIndex = index
}
// Company Profile
if viewcontroller.restorationIdentifier == companyProfileNavigation {
compProfileIndex = index
}
// My Calendar
if viewcontroller.restorationIdentifier == myCalendarNavigation {
myCalendarIndex = index
}
}
}
}
But this doesn't seem to work...what is it that I'm doing wrong...?

Swift Access Constraint from different View controller found nil

Hello I'm trying to access my constraint from my second view controller to my initial view controller, but it always give an error, Im accessing my constraint from a pageviewontroller class, to automatically adjust the height of my second page.
found nil while unwrapping optional value
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
return nil
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MainNeedPage") as! NeedDetailsController;
vc.bottomContainerHeight.constant = CGFloat(50)
vc.containerHeight.constant = CGFloat(30)
UIView.animate(withDuration: 0.5, animations: {
vc.view.layoutIfNeeded()
})
let nextIndex = viewControllerIndex + 1
let orderedViewControllersCount = orderedViewControllers.count
guard orderedViewControllersCount != nextIndex else {
return nil
}
guard orderedViewControllersCount > nextIndex else {
return nil
}
return orderedViewControllers[nextIndex]
}
Sh_Khan Answer worked, but when I want to get back to the first page of the pageviewcontroller it doesn't get back to it's original size. Here's what i've tried
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
let pageContentViewController = pageViewController.viewControllers![0]
var page = orderedViewControllers.index(of: pageContentViewController)!
if(page == 1) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MainNeedPage") as! NeedDetailsController
NeedDetailsController.status.viewstat = "true"
NeedDetailsController.status.bottomContainerHeightCon = CGFloat(50)
NeedDetailsController.status.containerHeightCon = CGFloat(30)
vc.view.layoutIfNeeded()
} else if(page == 0) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MainNeedPage") as! NeedDetailsController;
NeedDetailsController.status.viewstat = "false"
NeedDetailsController.status.bottomContainerHeightCon = CGFloat(50)
NeedDetailsController.status.containerHeightCon = CGFloat(30)
vc.view.layoutSubviews()
}
}
and on my initial controller
override func viewDidLayoutSubviews() {
print("statusx: \(NeedDetailsController.status.viewstat)")
if(NeedDetailsController.status.viewstat == "true"){
print("statusy: \(NeedDetailsController.status.viewstat)")
NeedDetailsController.status.viewstat = "false"
self.bottomContainerHeight.constant = 0
self.containerHeight.constant = 0
UIView.animate(withDuration: 1) {
self.view.layoutIfNeeded()
}
} else if(NeedDetailsController.status.viewstat == "false") {
print("statusz: \(NeedDetailsController.status.viewstat)")
setupview()
NeedDetailsController.status.viewstat = "old"
self.bottomContainerHeight.constant = 50
self.containerHeight.constant = 30
UIView.animate(withDuration: 1) {
self.view.layoutIfNeeded()
}
}
}
You can't access a property whose view controller is not loaded
vc.bottomContainerHeight.constant = CGFloat(50)
vc.containerHeight.constant = CGFloat(30)
try to add two variables to that class
var bottomContainerHeightCon:CGFloat!
var containerHeightCon:CGFloat!
set them like this
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MainNeedPage") as! NeedDetailsController;
vc.bottomContainerHeightCon = CGFloat(50)
vc.containerHeightCon = CGFloat(30)
and in viewDidLayoutSubviews
apply the variables to the constraints
override func viewDidLayoutSubviews
{
if(once){
once = false
self.bottomContainerHeight = bottomContainerHeightCon
self.containerHeight = containerHeightCon
self.view.layoutIfNeeded()
}
}

UIPageViewController crashing when not using static data

I have a working page view controller system with this ( just going to paste absolutely everything, pretty sure the issue just lies in my firebase observation near the top) :
class IndividualPeopleVC: UIViewController, UIPageViewControllerDataSource {
var pageViewController: UIPageViewController!
var pageTitles : [String]!
var imageURLS: NSArray!
let currentUser = FIRAuth.auth()?.currentUser?.uid
override func viewDidLoad()
{
super.viewDidLoad()
self.pageTitles = []
self.pageTitles = ["1", "2", "3", "4'"]
DataService.ds.REF_INTERESTS.child(passedInterest).child("rooms").child(passedRoom).child("users").observeSingleEventOfType(.Value) { (snapshot: FIRDataSnapshot) in
print(snapshot.value)
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots {
let name = snap.key
let uid = snap.value as! String
let person = Person(name: name, bio: "", UID: uid)
if person.UID != self.currentUser {
self.pageTitles.append(uid)
}
}
}
self.pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as! UIPageViewController
self.pageViewController.dataSource = self
let startVC = self.viewControllerAtIndex(0) as ContentViewController
let viewControllers = NSArray(object: startVC)
self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .Forward, animated: true, completion: nil)
self.pageViewController.view.frame = CGRectMake(0, 30, self.view.frame.width, self.view.frame.size.height - 60)
self.addChildViewController(self.pageViewController)
self.view.addSubview(self.pageViewController.view)
self.pageViewController.didMoveToParentViewController(self)
}
func viewControllerAtIndex(index: Int) -> ContentViewController
{
if ((self.pageTitles.count == 0) || (index >= self.pageTitles.count)) {
return ContentViewController()
}
var vc: ContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ContentViewController") as! ContentViewController
vc.titleText = self.pageTitles[index] as! String
vc.imageFile = self.pageImages[index] as! String
vc.pageIndex = index
return vc
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
{
var vc = viewController as! ContentViewController
var index = vc.pageIndex as Int
if (index == 0 || index == NSNotFound)
{
return nil
}
index--
return self.viewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
var vc = viewController as! ContentViewController
var index = vc.pageIndex as Int
if (index == NSNotFound) {
return nil
}
index++
if (index == self.pageTitles.count){
return nil
}
return self.viewControllerAtIndex(index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int{
return self.pageTitles.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int{
return 0
}
}
So basically most of that is just copy-pasted from another source and it works. It creates 4 pages from the pageTitles array that scroll and on another VC I am passing the 1,2,3 and 4 and a label is displaying everything in the array as the scrollview should.
The problem comes when I try to not hard-code the pageTitles and instead pull it from firebase.
When I comment out where I'm hard-coding the pageTitles array, I get an unexpected nil value on my ContentViewController where I'm sending the titles and I do like titleLabel.text = (what was sent over).
I figured maybe guarding it with an if/let to allow firebase time to load stuff in would help, so I did a
if let title = (what was sent over) {
titleLabel.text = title
}
Nothing shows up on the screen when this happens, and then if I scroll left or right I get an error with indexes down in my pagebefore/pageafters.
I feel like this should be super simple and very similar to a tableview? Load in data from firebase, fill an array with the info, use if/lets to allow firebase some time to load in, then update the UI based on the array.
I think your DataService is asynchronous. You have to create your pageviewcontroller once your data is ready. Try this modified viewDidLoad method.
override func viewDidLoad()
{
super.viewDidLoad()
self.pageTitles = []
// self.pageTitles = ["1", "2", "3", "4'"]
DataService.ds.REF_INTERESTS.child(passedInterest).child("rooms").child(passedRoom).child("users").observeSingleEventOfType(.Value) { (snapshot: FIRDataSnapshot) in
print(snapshot.value)
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots {
let name = snap.key
let uid = snap.value as! String
let person = Person(name: name, bio: "", UID: uid)
if person.UID != self.currentUser {
self.pageTitles.append(uid)
}
}
self.pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as! UIPageViewController
self.pageViewController.dataSource = self
let startVC = self.viewControllerAtIndex(0) as ContentViewController
let viewControllers = NSArray(object: startVC)
self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .Forward, animated: true, completion: nil)
self.pageViewController.view.frame = CGRectMake(0, 30, self.view.frame.width, self.view.frame.size.height - 60)
self.addChildViewController(self.pageViewController)
self.view.addSubview(self.pageViewController.view)
self.pageViewController.didMoveToParentViewController(self)
}
}

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