how to instantiate/ show a TableViewController - ios

I am struggling with this awful project for two weeks now and nothing seems to work. I have to do an app that loads some words from a server and presents them as pins on a map(MKView). I have to cluster the pins when the user zooms-out and for that I have used a this-party library written in Objective-C, but I also had to make a custom callout view with a button. When the user presses the said button the app should go to a TableViewController and here is my problem: I can't make it to do it. I have used before the "performSegueWIthIdentifier" and it worked very well, but now I get the error "there is no segue with '---' identifier". I know there are many other threads with this, but none of the solutions there work for me. Moreover, I have tried to instantiate the ViewController programmatically, but this does not work either because I get the "unexpectedly found nil..." and I don't know what to do any more.
I know I am doing something wrong, most probably how I call these functions, but I don't know what. This is what I have tried until now:
in the .xib file I have this:
import UIKit
class MarkerInfoView: MKAnnotationView {
#IBOutlet weak var theButton: UIButton!
#IBAction func readIt(sender: AnyObject) {
ViewController.goToArticles()
}
}
and in the ViewController:
class func goToArticles(){
ViewController().reallyGoToArticles()
}
I did this because I could not find another way to be able to call performSegueWithIdentifier or presentViewController
func reallyGoToArticles(){
println("let's go!")
let theArticlesSB = UIStoryboard(name: "Main", bundle: nil)
let vc = theArticlesSB.instantiateViewControllerWithIdentifier("theArticles") as! articlesViewController
self.presentViewController(vc, animated: true, completion: nil)
self.performSegueWithIdentifier("showArticles", sender: self)
}
I have uncommented both options just to show you.
I have uploaded the project here
Thank you very much!
Update
I forgot to mention that if I put the line
self.performSegueWithIdentifier("showArticles", sender: self)
in viewDidLoad it works

I had a look at your project and found your issue.
In MarkerInfoView.swift, you call ViewController.goToArticles() which is a class function:
class func goToArticles(){
ViewController().reallyGoToArticles()
}
This class function creates a NEW instance of ViewController which has nothing to do with the storyboard (and is not aware of segues).
You have to call self.reallyGoToArticles() from an instance method like
func goToArticles(){
self.reallyGoToArticles()
}
You have to manage to call the existing ViewController from your MarkerInfoView
EDIT: Here is how to achieve it
MarkerInfoView.swift
class MarkerInfoView: MKAnnotationView {
var vc: ViewController!
#IBOutlet weak var placePhoto: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var detailsLabel: UILabel!
#IBOutlet weak var theButton: UIButton!
#IBAction func readIt(sender: AnyObject) {
vc.goToArticles()
}
}
ViewController.swift
func mapView(mapView: MKMapView!, didSelectAnnotationView annotation: MKAnnotationView!)
{
if let pin = annotation.annotation as? CustomPointAnnotation{
if var infoView = UIView.viewFromNibName("MarkerInfoView") as? MarkerInfoView {
infoView.nameLabel.text = pin.theTitle
infoView.detailsLabel.text = pin.theDetails
infoView.vc = self
infoView.center = CGPointMake(self.view.bounds.width/2, self.view.bounds.height/2)
self.view.addSubview(infoView)
} else {
}
}
}
func goToArticles(){
self.reallyGoToArticles()
}

Related

UIView Extension does not work on app first launch

I am using the following UIView extension:
https://github.com/snoozelag/GoneVisible
I have successfully downloaded the file and added the Swift file and I am using the extension to hide (gone method) and show (visible method) buttons on the navigation bar. When the app first opens, I call this extension in an attempt to hide certain buttons if the user is already logged in. However, this has not been working. Strangely, it DOES work and hides the buttons after I segue to a different view and go back.
Here is the code:
import UIKit
import Parse
class ViewController: UIViewController {
#IBOutlet weak var signUpButton: UIButton!
#IBOutlet weak var logInButton: UIButton!
#IBOutlet weak var myAccountButton: UIButton!
#IBOutlet weak var bigGame: UIImageView!
private func setUpPage(){
let currentUser = PFUser.current()
if currentUser != nil {
// Do stuff with the user
self.myAccountButton.visible()
self.signUpButton.gone()
self.logInButton.gone()
} else {
// Show the signup or login screen
self.myAccountButton.gone()
self.signUpButton.visible()
self.logInButton.visible()
}
}
override func viewDidLoad() {
setUpPage()
super.viewDidLoad()
self.navigationItem.hidesBackButton = true;
}
override func viewWillAppear(_
animated: Bool) {
setUpPage()
}
My question is, how can I get this extension to fire when the app is first opened?
Thanks a lot for your help :)
Don't forget to call super.viewWillAppear(...) when you override the inherited implementation.
This might solve your issue - but even if not it is correct to do it.
Update:
try calling setUpPage() only once and only after you call super.viewDidLoad()

UISwitch value inside a nib does not being updated

My switch is inside of a nib which is inside of a tableview header. When I click the switch it only does the pushSwitch.isOn and not !pushSwitch.isOn. It only gives me the values inside of the pushSwitch and doesn't seem to go inside of !pushSwitch.isOn
Thanks
protocol PhoneNotificationHeaderViewDelegate: class {
func copyPreferredSettingsRequested()
func textNotificationSwitchTapped()
func pushNotificationSwitchTapped()
}
class PhoneNotificationHeaderView: UITableViewHeaderFooterView {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var textSwitch: UISwitch!
#IBOutlet weak var pushSwitch: UISwitch!
#IBOutlet weak var copyPreferredSettingsButton: UIButton!
#IBOutlet weak var notificationView: UIView!
weak var delegate: PhoneNotificationHeaderViewDelegate?
UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
}
#IBAction func textNotificationSwitchTapped(_ sender: AnyObject) {
self.delegate?.textNotificationSwitchTapped()
}
#IBAction func pushNotificationSwitchTapped(_ sender: UISwitch) {
self.delegate?.pushNotificationSwitchTapped()
}
#IBAction func copyPreferredSettingsButtonTapped() {
self.delegate?.copyPreferredSettingsRequested()
}
override var backgroundColor: UIColor? {
didSet {
print("backgroundColor")
}
}
Here is my switch inside my VC:
extension PhoneNotificationViewController: PhoneNotificationHeaderViewDelegate {
func pushNotificationSwitchTapped() {
guard let phoneNotificationHeader = Bundle(for: type(of: self)).loadNibNamed("PhoneNotificationHeaderView", owner: self, options: nil)?.first as? PhoneNotificationHeaderView else {
return
}
if phoneNotificationHeader.pushSwitch.isOn{
//Disable Firebase from sending
Globals.sharedInstance.pushStatus = true
phoneNotificationHeader.pushSwitch.setOn(false, animated: true)
}else{
Globals.sharedInstance.pushStatus = false
phoneNotificationHeader.pushSwitch.setOn(true, animated: true)
}
self.refreshUI()
}
There is no such thing as a "a nib which is inside of a tableview header". Every time you load a nib by saying loadNibNamed, you get a fresh copy of the view that it contains. So every time you call pushNotificationSwitchTapped you are a getting a whole new switch fresh from the nib, and sticking it in your interface. That is probably not what you intend! And of course the switch comes from the nib in only one state, namely the state that you set it in the nib editor: it is On.
You need to abandon completely this incorrect architecture based on a misapprehension about what a nib is. You should load the nib once, and from then on you should refer to the switch by talking to the switch itself, the one that is now in your interface.

Using shared classes for different views

I have an onboarding user flow:
Name -> Age -> Gender
Each of the screens shares the same structure:
Question (top)
Input (middle)
Continue (bottom)
I have a class OnboardingHelper.swift that creates a class to set the question box and continue button:
class UserOnboardingHelper{
var text: String
var questionbox: UIView
var viewController: UIViewController
var continueButton: UIButton
init(text: String, questionbox: UIView, viewController: UIViewController, continueButton: UIButton){
self.text = text
self.questionbox = questionbox
self.viewController = viewController
self.continueButton = continueButton
}
func setQuestionBox(){
//sets question box
}
func setContinueButton(){
//sets continue button
enableContinueButton()
addContinueButtonPath()
}
func enableContinueButton(){
//enables continue button
}
func disableContinueButton(){
//disables continue button
}
func addContinueButtonPath(){
//sets path of continue button based on which view
}
}
In each of the onboarding ViewControllers I am setting the class in ViewDidLoad():
class NamePageViewController: UIViewController, UITextFieldDelagate {
#IBOutlet weak var questionbox: UIView!
#IBOutlet weak var continueButton: UIButton!
#IBOutlet weak var inputLabel: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let namePageSettings = UserOnboardingHelper(text: "What is your name", questionbox: questionbox, viewController: self, continueButton: continueButton)
namePageSettings.setQuestionBox()
namePageSettings.setContinueButton()
inputLabel.delegate = self
if nameIsFilled {
namePageSettings.enableContinueButton()
} else{
namePageSettings.disableContinueButton()
}
}
}
The issue is that in the ViewController I textFieldDidEndEditing() function which needs to call the namePageSettings class from viewDidLoad()
func textFieldDidEndEditing(_ textField: UITextField){
if (textField.text?.empty)!{
//I want to call disableContinueButton() from UserOnboardingHelper
} else {
//I want to enable enableContinueButton() from UserOnboardingHelper
}
}
Trying to understand if:
The overall approach is correct and if not, what's the best way
If the above approach is in the right direction, how should disableContinueButton() and enableContinueButton() be called?
Thanks in advance! Sorry if the approach is really dumb - I'm still trying to wrap my head around classes.
You can have the view controller have a weak reference to the onboarding helper, so you can still call helper methods without creating a retain cycle.
In NamePageViewController, add a property:
weak var userOnboardingHelper: UserOnboardingHelper?
Then, in UserOnboardingHelper's initializer, add:
self.viewController.userOnboardingHelper = self
You can now call the onboarding helper's methods in the view controller:
userOnboardingHelper.disableContinueButton()
userOnboardingHelper.enableContinueButton()

How do I set the text on my UILabel on one ViewController to pull from another ViewController?

I created a UILabel called order1label on my ThirdViewController.
I want text to be displayed on that label based on what is decided in my SecondViewController.
Below is the code for those two view controllers. When I click on the Submit UIButton in the SecondViewController, I expect the orderType to change to Delivery on the ThirdViewController, and I expect that to be reflected in order1label, but it is not. It still says Takeout.
What am I doing incorrectly? I've been searching for answers for hours and there does not appear to be a simple solution to this extremely simple problem.
import UIKit
class SecondViewController: UIViewController{
var orderType = "Takeout"
#IBAction func SubmitOrderClicked(sender: UIButton) {
orderType = "Delivery"
}
}
Here is the code for my ThirdViewController:
import UIKit
class ThirdViewController: UIViewController {
var orderTextController = SecondViewController().orderType
override func viewDidLoad() {
super.viewDidLoad()
order1Label.text = orderTextController
}
override func viewWillAppear(animated: Bool) {
order1Label.text = orderTextController
}
#IBOutlet var order1Label: UILabel!
}
Declare a global variable orderType in SecondViewController like:
import UIKit
var orderType = "Takeout"
class SecondViewController: UIViewController{
#IBAction func SubmitOrderClicked(sender: UIButton) {
orderType = "Delivery"
}
}
Here is the code the ThirdViewController:
import UIKit
class ThirdViewController: UIViewController {
override func viewWillAppear() {
super.viewWillAppear()
order1Label.text = orderType
}
#IBOutlet var order1Label: UILabel!
}
Hope this satisfies your requirements. Happy coding.
I'm supposing that you want to present ThirdViewController when tapping the button on SecondViewController, so you'd need to change the code to:
import UIKit
class SecondViewController: UIViewController{
var orderType = "Takeout"
#IBAction func SubmitOrderClicked(sender: UIButton) {
orderType = "Delivery"
let thirdController = ThirdViewController()
thirdController.order1Label.text = orderType
self.present(thirdController, animated: true, completion: nil)
}
}
When you call present, the view controller you specify will load and will enter to viewDidLoad. You'd also need to remove this
var orderTextController = SecondViewController().orderType
your problem is only because the label in thirdController needs to be informed after the text is changed in secondController.
After changed your text by clicking the button, you need to inform the label in thirdController to also change the text.
There are several ways that you can achieve that, delegate, notification, block and so on.
If you have further question about using any of ways above please tell me.

Understanding delegates in iOS programming

I am new to iOS programming and I'm trying to understand and begin implementing delegates to get information between view controllers and any other use they may have.
I've used this topic to get a little further, but I can't comment as i just created this account, so i can't ask a question on the post. I copied drewag's example but this line
#IBOutlet weak var delegate: ViewControllerBDelegate?
is giving me an error "IBOutlet property cannot have non-object type SecondViewControllerDelegate"
I deleted it and it runs but the information is not being sent between the two view controllers. I thought i was beginning to understand delegates but just getting them implemented is beginning to get frustrating. I've been at this for a few days now.
FirstViewController:
class FirstViewController: UIViewController, SecondViewControllerDelegate {
#IBOutlet weak var theMap: MKMapView!
func requiredText() -> String {
return "test"
}
SecondViewcontroller:
protocol SecondViewControllerDelegate {
func requiredText() -> String
}
class SecondViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var delegate: SecondViewControllerDelegate?
#IBAction func decide(sender: AnyObject) {
if let actualDelegate = self.delegate {
self.label.text = actualDelegate.requiredText()
}
}
So my question simply is what am I doing wrong? I thought i followed the example correctly.
You need to declare SecondViewControllerDelegate like this:
#objc protocol SecondViewControllerDelegate {
func requiredText() -> String
}
This is just a quirk of the Swift compiler or the runtime. The #objc directive makes the compiler emit additional information about the protocol. At runtime, the program uses that information to verify the delegate implements the protocol's methods. Since these objects are loaded from a xib (or storyboard), the compiler can't verify it at compile time.
You do not set your actualDelegate = firstViewController,so actualDelegate is always nil.
If you use storyboard,set Identifier of firstViewController as "first"
then
override func viewDidLoad() {
super.viewDidLoad()
let storyboard = UIStoryboard(name: "Main", bundle: nil);
var firstview = storyboard.instantiateViewControllerWithIdentifier("first") as FirstViewController?;
self.delegate = firstview;
// Do any additional setup after loading the view, typically from a nib.
}

Resources