Nothing major, but I thought it’s good if I start noting them.
Page 714, return imageView.hidden ? 44 : 280 → isHidden
Page 714, there tmust be → must
Nothing major, but I thought it’s good if I start noting them.
Page 714, return imageView.hidden ? 44 : 280 → isHidden
Page 714, there tmust be → must
Thank you I’ll make sure that these are fixed in the next update.
Thanks.
Later on this code really puzzled me:
var cell: UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
if cell == nil {
Here we are making a variable which can not be nil, into possibly nil state, or I am not really understanding it right. Why are we allowed to do this? It seems to me like a new concept introduced here, but it’s not explained. The logical way would be to simply use cell! in the lower lines.
Actually, a different problem, but linked to this, is on page 806 reading the needed change of the same code was quite difficult. It’d make more sense to me to follow the logic of:
or something like this. I don’t know but this part is the first part since 800 pages where I really struggled in understanding.
Ah, I see where the confusion comes from - my apologies for the slightly complicated code
Basically, there are two slightly different variations of dequeueReusableCell
- one returns an optional the other does not. The one which returns a non-optional takes an additional parameter for the indexPath
. I believe I’ve used both the variations in different parts of the book, but if I use the optional variation, I usually write it something like this:
if let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) {
}
So that it is clearer and cleaner. In the above code, I’m simply declaring cell
as a force-unwrapped UITableViewCell
. This allows me to use cell
in later code without having to use optional syntax but since the variable is force unwrapped, it could still contain nil
. Hence the check for nil
on the second line you provided. Does that make sense?
The code might be easier to read if it was written something like this:
var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
if cell == nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: cellIdentifier)
}
Only difference is that any references to cell
after that point would need to use optional syntax like cell?.textLabel!.text
and you’d have to force unwrap cell
when you return it from the method too since I believe you need a non-optional at that point. I probably wrote the code the way it is in the book to bypass these issues
Thanks. Indeed before this point, everywhere in the book, a variable was like in your second example of your reply, which felt natural to me after reading it in so many pages.
I believe it was mentioned somewhere that for-unwrapped class variables had to be non-nil by the end of init()
, which also makes sense for me.
But now you are writing that
Which confuses me, how can a force-unwrapped variable contain nil?
I also wanted to look it up in Apple’s Swift 4 manual, but didn’t find where this is explained, if you can link to a reference it’d also help, so I could read about it in detail.
OK, I think I found some bits. Aren’t they called “implicitly unwrapped optionals”?
So if I understand them right, they are allowed to be nil, temporarily, you are just not allowed to actually access them, but checking for nil
doesn’t count as accessing? So you can check for nil, and make sure they are set.
Page 846, “Add the following method:” → To which part?
Usually in cases like this it’s always mentioned (and now SearchViewController has 3 parts actually).
The main body of SearchViewController looked the best candidate, but I had to manually check from _final.zip.
On page 850, is there any reason for having
case kind, artistName, trackName
case trackPrice, currency
as two separate case lines?
Chap 4, p. 91:
The book discusses where to call updateLabels(), and the decision was to call updateLabels() inside startNewRound(). But at the end of the chapter on p. 92, the book refers to the book’s downloadable code:
04 - Outlets
to see the current state of the code, and in that code there is this:
@IBAction func showAlert() {
...
startNewRound()
updateLabels() //***WRONG!!***
}
updateLabels() is already being called in startNewRound(), so calling it after startNewRound() is redundant.
Chap 7, p. 152:
I believe UIWebView has been deprecated since at least IOS 9, so I’m not sure why it is appearing in apps written for IOS 11. In Xcode 9.1, when you try to drag a UIWebView onto the storyboard, the UIWebView even has a little note that says it’s deprecated.
Also, I was confused by why webView.load()
required a url parameter when it is loading a Data() object that already contains the html. Afterall, if load() already has the html, it doesn’t have to go out on the web to download the html, so why do you have to pass a url to load()? I searched around, and I couldn’t find any information about that. It wasn’t until I decided to convert the code to use a WKWebView that I discovered why a url is needed. From the WKWebView docs:
baseURL
A URL used to resolve relative URLs within the document.
An html page can have links inside it with relative paths, e.g.
<a href="free_bit_coins.html">Click me</a>
A browser takes the relative path, free_bit_coins.html, and adds it to the “base url” displayed in the location bar in the browser to create the full url for the page. Therefore, when you load a Data object that already contains the html you still need a base url so that any relative paths inside the html document can be resolved to the proper location. In our case, the base url happens to be a file path to our project folder, and we don’t have any imbedded links in the html.
It really doesn’t matter which section you add the code to. Unlike playgrounds where the order of the code matters, it doesn’t really matter where you put a method as long as it is part of the class. So adding it to any section should generally work. But I’ll clarify in the next release.
Nope, just organizational. You can have it all on one line if you like
Yes, this will be updated for WKWebView in the next release. Since you’ve answered your own question for the rest of it, I will simply add a clarification about the base URL when we do an update as well.
Personally, this looks cleaner in multiple lines:
enum CodingKeys: String, CodingKey {
case imageSmall = "artworkUrl60"
case imageLarge = "artworkUrl100"
case itemGenre = "primaryGenreName"
case bookGenre = "genres"
case itemPrice = "price"
case kind, artistName, currency,
trackName, trackPrice, trackViewUrl,
collectionName, collectionViewUrl, collectionPrice
}
Chap 8, p. 157:
The books says:
In order for the background image to stretch from edge-to-edge on the screen, the left, top, right, and bottom edges of the image should be flush against the screen edges. The way to do this with Auto Layout is to create two alignment constraints, one horizontal and one vertical.
Then the first thing we do is add four constraints. I found it confusing that the book said we were going to create two constraints, and then we immediately created four constraints. Maybe the book should say something like:
The way to do this with Auto Layout is to create constraints that fix the position of the background image both horizontally and vertically.
Chap 8, p. 161:
This concerns the constraints for the “Close” button on the About page. The book says:
Interface Builder now draws a red bar to represent the constraint, and a red box around the button as well.
In Xcode 9.1, I see a blue vertical bar–not a red bar–which makes sense to me because the button is constrained precisely in the horizontal direction, i.e. in the middle of the container, so I’m not sure why the vertical bar representing that constraint would be red.
I do get a red horizontal bar above and below the Close button as well as a compiler warning that says:
Ambiguous Layout
Vertical position is ambiguous for "Close".
…which is something I would expect because there is no vertical constraint for the Close button. Should the book say “blue bar” in the quote above, or am I seeing aberrant behavior in Xcode 9.1?
On page 920, it says: “If you take a look at the image info, you will see that it is only 11 points wide. That means it has a 5-point cap on the left, a 5-point cap on the right, and a 1- point body that will be stretched out.”
Where exactly can I look at the image info? All I see is 22x48 pixels for 2x and 33x72 pixels for 3x, but I don’t see image dimensions in points anywhere.
Perhaps this should have been made clearer in the text but since you can get the point size for a 2x image by dividing by 2 (and for a 3x image by dividing by 3) I simply divided the image width, which is 22, by 2 to get 11. I will add something to clarify this in the next update.
I see. The most important information there (missing) is that for 2x, set the left and right to 10px, for 3x set the left and right to 15px in the inspector / slicing.
on page 940 => Toggle Larger Accessibility Sizes to on and drag the slider all the way to the right. That gives you the maximum font size (it’s huge!).
If I toggle larger sizes first and then move to the now HUGE rightmost position, the view I get is not the one in the book but something unreadably extremely huge. I mean with this setting even the settings app is barely navigatable on an iPhone SE.
p. 289, Chapter 13:
The protocol declaration uses the class
keyword(?). There’s no explanation in the text of what that does, and it looks like a typo. I vainly searched around enough for an explanation that I was pretty sure it was a typo. I turns out that the Apple docs changed: they now use AnyObject
instead of class
to limit the application of a protocol to classes. So, I think the text needs to either change class
to AnyObject
in order to be consistent with the docs, or if the docs are in error, then the text needs to mention what class
does.
Maybe it would be simpler not to limit the protocol to classes and not use weak
for the delegate variable?