Search code examples
iosuiviewcontrollerswift2alamofirensobject

textLabel.text in UIViewController comes up nil while assigning string from NSObject


I'm an iOS and programming noob so I apologize for any bad phrasing or mistakes.

I'm parsing quotes from an API for my app which displays it on a textLabel each time a UIButton is clicked. In order to keep the string from going off the textLabel or be resized to an unreadable font, I'm trying to request a new quote if the string character count is too high by calling a function in my NSObject. I set up a NSObject to do the refetching but whenever I try to reassign the the string to the textLabel.text from the NSObject or try to send the string back to the ViewController the qouteLabel.text comes back nil

Here is my viewcontroller where I'm making the initial request for the quote

    import UIKit
import Alamofire

class RSQuotesViewController: RSViewController {


    var ronImageView: UIImageView!
    var quoteLabel = UILabel!()


    override func loadView() {
        let frame = UIScreen.mainScreen().bounds
        let view = UIView(frame: frame)
        view.backgroundColor = UIColor.grayColor()



        ronImageView = UIImageView(frame: CGRectMake(frame.width/2-160, frame.height-600, 320, 600))
        let ron = "ron.png"
        let ronImage = UIImage(named: ron)
        ronImageView.image = ronImage
        view.addSubview(ronImageView);

        let labelWidth = ronImageView.frame.width/2
        let quoteLabelX = labelWidth-40

        quoteLabel = UILabel(frame: CGRect(x: quoteLabelX, y: ronImageView.frame.height/4+15, width: labelWidth, height: 160))
        quoteLabel.textAlignment = .Center
        quoteLabel.text = "Click to Start"
        quoteLabel.shadowColor = UIColor.grayColor()
        quoteLabel.adjustsFontSizeToFitWidth = true
        quoteLabel.lineBreakMode = .ByWordWrapping // or NSLineBreakMode.ByWordWrapping
        quoteLabel.numberOfLines = 0
        view.addSubview(quoteLabel)


        self.view = view
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let frame = UIScreen.mainScreen().bounds

        let getQuote = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width+50, height: frame.size.height))
        getQuote.backgroundColor = UIColor.clearColor()
        getQuote.setTitle("", forState: UIControlState.Normal)
        getQuote.addTarget(self, action: #selector(RSQuotesViewController.getQuote(_:)), forControlEvents: UIControlEvents.TouchUpInside)

        self.view.addSubview(getQuote)

    }



    //  Gets quote when button is pressed
    func getQuote(sender: UIButton){
        let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
        Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
            if let JSON = response.result.value as? Array<String>{
                let quoteDict = RSQoute()

                // if quote is too large get another one
                if (JSON[0].characters.count > 120){

                    print("greater than 120")
                    quoteDict.fetchQuote()

                } else {

                    self.quoteLabel.text = JSON[0]


                }





        }


    }

}

This is my model where I'm trying to reassign the quoteLabel.text and getting nil

import UIKit
import Alamofire

class RSQoute: NSObject {

    var newQuote = String()


    //   fetchs new quote if quote is too large

    func fetchQuote(){

        let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
        Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
            if let JSON = response.result.value as? Array<String>{
            self.newQuote = JSON[0]
                if (self.newQuote.characters.count > 120) {

                    print("Try Again: ---->\(self.newQuote)")
                    return self.fetchQuote()
                } else {
                    let quoteVC = RSQuotesViewController()
                    print("Retry was less than 120: ---->\(self.newQuote)")
                    print("quoteLabelText: ---->\(RSQuotesViewController().quoteLabel.text)")// comes back nil
                    RSQuotesViewController().quoteLabel.text = self.newQuote

                }




        }
    }
    }



}

Please let me know if there something I'm missing or an easier/better way of trying to fetch a new quote from the API :)


Solution

  • In your function fetchQuote(), you set quoteVC as a new instantiation of RSQuotesViewController() with let quoteVC = RSQuotesViewController(). Instead you should be setting the quoteLabel.text for the applications instance of RSQuotesViewController(). You are also making two API requests. Once inside the fetchQuote() function for RSQuotesViewController and once inside your fetchQuote() function for RSQuotes


    I think what you are looking for would involve closures. Try this out for your fetchQuote() function in your RSQuotes class

        func fetchQuote(completion: (result:String)){
    
        let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
        Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
            if let JSON = response.result.value as? Array<String>{
            self.newQuote = JSON[0]
                if (self.newQuote.characters.count > 120) {
    
                    print("Try Again: ---->\(self.newQuote)")
                    completion(result: self.newQuote)
                } else {
                    print("Retry was less than 120: ---->\(self.newQuote)")
                    print("quoteLabelText: ---->\(RSQuotesViewController().quoteLabel.text)")// comes back nil
                    completion(result: self.newQuote)
    
                }
        }
    

    Then, I would have a setQuote function RSQuotesViewController where you could just do something like this

    func setQuote() {
        let quoteObj = RSQuote()
        quoteObj.fetchQuote() {
             result in
             quoteLabel.text = result
        }
    } 
    

    I would take a look at some posts related to swift closures and also check out. http://goshdarnclosuresyntax.com/


    On a side note, I'm not sure if you were planning to manipulate the quoteString within your RSQuote class. If not, it might be better for fetchQuote() to be a static func. This way you can just call it without initializing the object in RSQuoteViewController. It'd be something like RSQuote.fetchQuote()