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

Extra credit: Modify the CrystalBall class to work without the @property predictions

iOS - Stage 4 - Refactoring into a Model

I must be missing something.

I just comment out

//@property (strong, nonatomic, readonly) NSArray *predictions;

and the app compiles and runs just fine.

Can anyone shine some light on what was supposed to happen, and this line seems to be not required?

Thanks!

7 Answers

To add my two cents to this discussion, the reason we declared the predictions property in the first place was so that we could add data to it. We added data to it by defining our own setter method, which is the actual method that @property would have set up for us behind the scenes, however, given we needed to add data to this setter, we declare it ourselves instead.

Now then, as the tutorial notes, there is a vulnerability to this property as its setter data can be manipulated, which is why we then set it to readonly. The side effect of the property now being readonly is the removal of its setter and getter methods. This means goodbye _predictions and all of its data. To resolve this issue, we then declare an instance variable of the same name (_predictions) on the class itself. Whilst the name is actually quite self-explanatory, not changing it in this tutorial leads you to think it's still a setter, which it isn't.

By this point, the predictions property is no longer required and is actually redundant. The reason why the build succeeds with the predictions property still in place is because it the compiler sees no problem creating properties that aren't used in any way, however, it's bad practice to write redundant code.

Just ran into the same problem. No clue if this is still relevant for you, Jayson, but I think the reason it still works when you comment the @property code out, is that we already declared the instance variable NSArray *_predictions within NSObject in THCrystalBall.h

Amit spoke about getter and setter methods, and declaring the instance variable is the old-fashioned way of doing it, I believe. Not sure if this is actually the right answer, though.

A purpose for the @property directive is to synthesize a variable with the proper setter and getter, in this case only a getter. Since it is only used within the object, do you really need a getter? Or can you access the NSArray in some other way? (don't forget to initialize it at some other point after removing the getter)

Apparently, I'm already accessing the array in some other way. If I remove the @property and don't modify the class, the program still works. So, it would appear as though the @property was superfluous to begin with. That's why I'm confused.

Glad to know it's working. Is it initialized though? :)

Some additional comments:

The way how dot notation works in Objective-C can be confusing to some without knowing its history prior to being introduced in 2.0 or taking the time to appreciate the underlying processes.

self.predictionLabels, when used to access its value or when sent a message (method call), is replaced before compiling by something similar to [self predictionLabels] (or in other languages nomenclature [self getPredictionLabels]). While when used for assignment, it is equivalent to calling the method [self setPredictionLabels:someValue]. Hence the dot notation represents two possible methods being called depending on context. This approach is beneficial in that it allows type check, conversion, and any other codes such as KVO to be called every time the variable is accessed (get/set).

This is vastly different from many other object-oriented languages, where dot notation simply generates a pointer to a variable, which is no different from using _predictionLabels. Thus in other languages you often see the pattern of defining a separate get/set method to handle extra tasks such as validating a set.

I really appreciate the response. Unfortunately, it means absolutely nothing to me. :) Still just learning...

Is there any way to complete this extra credit challenge without creating any new vulnerabilities or using a sub-par coding practice? The way I first thought of is creating the predictions array in the randomPrediction method of the CrystalBall class. The problem here is that even though there is no longer a prediction property, the Array will be built every time the method is called. I believe Amit said that this is not the best practice which is why he had us move it into the Model and out of the IBAction method.