Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Fun FactBook App and Parse

Hi

I wanted to take the FactBook application using Swift a little further and integrate Parse.

I have successfully integrated Parse via their doc instructions and created a bridging header file but I'm not too sure on the process of integrating the quotes.

Would you recommend when the app is launched it downloads all of the Facts and stores them on the phone locally and then on each refresh the app calls from that array or it makes a new network call each time?

I'm not too sure which road is the best to go down... Memory Vs. Network.

Moving onto the actual code. If anyone has done anything similar it would be much appreciated for those wanting to take the Fun FactBook a little further, a brief overview of the code required to getting something to work!

Thanks :)

1 Answer

it kind of depends on the number of facts you have. if you have a lot of facts it might take more time than you think is acceptable to download them all at once. if you have 20 or so getting them all when the app starts is probably fine.

I think I would get a new one from the backend each time.

Thanks. I have well over 200 quotes. I thought that would be far too much to store in memory but didn't know if the network calls would become a poor UX.

an array of 200 text quotes is not that big honestly. you should just try out both ways of doing it and see what you think is best. use a loading indicator whenever you get data from the backend to let the user know work is being done. both ways have disadvantages and advantages

Thanks. Do you have any experience using Parse?

I'm in the middle of adding it to my project and I'm doing something like this to add the quotes to an array.

func loadData() {
    var findFactsData:PFQuery = PFQuery(className: "Facts")

    findFactsData.findObjectsInBackgroundWithBlock{
        (objects:[AnyObject]! , error:NSError!) -> Void in
        if error != nil {
            for object:AnyObject in objects! {
                self.factsData.addObject(object as PFObject)
            }
        }
    }

    self.quotesCount = self.quotesData.count
}

I'm running that method inside viewDidLoad() and the factsData is a NSMutableArray but once I've got that. I'm unsure how I should be referencing to it within my other views and getting a random quote from there.

self.quotesCount = self.quotesData.count appears to be 0 when I print it to the console. So either the query isn't working or at the time that code is ran, the array is ZERO because the findObjectsInBackgroundWithBlock hasn't ran yet. I'm not sure when it has completed I can set the quotesCount

Thanks

Update: I tried adding

dispatch_async(dispatch_get_main_queue(), {
            self.factsCount = self.quotesData.count
            println("Updated facts count: \(self.factsCount.count)")
        })

But that also returns 0. The query I would imagine is running because the status bar displays a spinner but it appears it doesn't return anything.

I would probably just use a regular array. looping over the objects and adding them one by one takes time compared to just setting an array property using the objects array.

findFactsData.findObjectsInBackgroundWithBlock{
        (objects:[AnyObject]! , error:NSError!) -> Void in
        if error != nil {
            self.factsData = objects
        }
    }

also yes since the findObjects method runs in the background quotesCount is getting set before the quotesData. wait you have factsData and quotesData, what is the difference between those two?

if you have done the fun facts app you should have a model class. that is where this code needs to go.

Ignore the two variable arrays. I tried creating another one for a moment using another name to see if it worked using another query but same result. I got rid of the model for now to try getting this to work in the controller. I'll try adding it to the model created during the course.

yeah you can get it to work in view did load. try moving the log into the findObjects function completion block after you add all the objects

func loadData() {
    var findFactsData:PFQuery = PFQuery(className: "Facts")

    findFactsData.findObjectsInBackgroundWithBlock{
        (objects:[AnyObject]! , error:NSError!) -> Void in
        if error != nil {
            for object:AnyObject in objects! {
                self.quotesData.addObject(object as PFObject)

            }
            self.factsCount = self.quotesData.count
            println("Updated facts count: \(self.factsCount.count)")
        }
    }


}

I think I'm thinking this too much here. I am not getting an error NSArray does not have a member named 'addObject'

sorry, did you change your mutable array property to a regular array? are you using NSArray or a swift array? if you are using a swift array try

func loadData() {
    var findFactsData:PFQuery = PFQuery(className: "Facts")

    findFactsData.findObjectsInBackgroundWithBlock{
        (objects:[AnyObject]! , error:NSError!) -> Void in
        if error != nil {
            self.quotesData = objects
            self.factsCount = self.quotesData.count
            println("Updated facts count: \(self.factsCount.count)")
        }
    }


}

you may have to do some casting

 self.quotesData = objects as [PFObject]

Sorry! I noticed I had changed it from a NSMutableArray to a NSArray. Nothing prints out however in the console even when the above code is inside the viewDidLoad() method.

Very strange!

oh i see whats wrong. your if condition is incorrect. you have

if error != nil {

but you need

if error == nil {

Ok. It's giving me an error back unexpectedly found nil while unwrapping an Optional value and that'll be because some of the facts have author fields and some don't. Is there a way to make this nil if it doesn't exist within the array?

Edit: I got the query to work it seems but now pulling a random one from the array and choosing the factLabel?.text = fact["fact"] doesn't seem to work.

It's complaining about AnyObject does not have member named "subscript"