Chapter 26: Adding Polish :: Page 599 Deactivate the Keyboard

The 3rd example of writing the if statement causes all rows == 0 to not resignFirstResponder() regardless of their section.

hideKeyboard() method, first if statement example (pg 598) :: Works

@objc func hideKeyboard(_ gestureRecognizer: UIGestureRecognizer) {  
  let point = gestureRecognizer.location(in: tableView)
  let indexPath = tableView.indexPathForRow(at: point)

  if indexPath != nil && indexPath!.section == 0
                      && indexPath!.row == 0 {
    return
  }
  descriptionTextView.resignFirstResponder() 
}

If statement alternative way 2 (pg 599) :: Works
if indexPath == nil ||
          !(indexPath!.section == 0 && indexPath!.row == 0) {
  descriptionTextView.resignFirstResponder()
}
If statement alternative way 3 (pg 599) :: Broken
if let indexPath = indexPath, indexPath.section != 0 &&
                              indexPath.row != 0 {
  descriptionTextView.resignFirstResponder()
}

If statement alternative way 3 (pg 599) :: Fix
Allows for any row == 0, except for that in section 0, to resignFirstResponder()

if let indexPath = indexPath, !(indexPath.section == 0 &&
                                indexPath.row == 0) {
descriptionTextView.resignFirstResponder()
}

As a Guard let statement :: Works, but I have a question about shadowing indexPath

guard let path = indexPath, !(path.section == 0 &&
                              path.row == 0) else { return }
descriptionTextView.resignFirstResponder()

I get an error when I try to shadow indexPath? in assigning it indexPath via guard let.
Error 'Definition conflicts with previous value' in the same method

let indexPath = tableView.indexPathForRow(at: point) // conflicting def

I had to assign it to a different constant name, so I chose path.

Question: Is there a way to write this that would allow me to shadow indexPath? using guard let? Or would I always have to chose a different constant name in situations like this?

Thanks so much!
Rebecca - i2j3

The above code compiles fine over here when I try :slight_smile: So not sure why it is broken at your end but Xcode does sometimes throw out false positives and I wonder if that is the case here?

Of course, this could be a Swift version issue too since I’m testing on Swift 4.2 on Xcode 10 beta. But it should work even on Xcode 9 though there might be differences between Xcode 9.0 (when the code was written and tested) and Xcode 9.4 which I believe is the latest? But since it works on Xcode 10, I believe it should still work …

As for the guard statement, you would have to use a different variable there since you aren’t actually shadowing there but rather, creating a new variable instance. The shadowing works, if I’m not mistaken because the variable is there only for the scope of the if statement. But guard creates a new variable that is in scope for the rest of the method.

Hope that makes sense?

I think broken was the wrong word. Sorry, the issue is that when you build it, and tap on any row who’s indexpath.row is 0, it won’t resignFirstResponder(). The other if statements do it just fine when I build and tap on any row 0 in any section other than section 0.

Edit for clarity: It’s as if it’s treating the && as an || on my end for some reason. I was only able to make it treat it as && via

if let indexPath = indexPath, !(indexPath.section == 0 &&
                                indexPath.row == 0) {
descriptionTextView.resignFirstResponder()
}

Yes! Thank you for the explanation!
Rebecca - i2j3

Ah, you mean it was logically wrong rather than syntactically wrong :slight_smile: OK, didn’t check the logic. Will make a note to check for the next release of the book since I’m in the middle of updating the book anyway. Thanks!

Ah I see, broken should be used for Errors, Syntactics, Bugs? And for logic - state that there might be an error in the logic?

Oh, not saying that you stated the issue incorrectly :slight_smile: Just saying that’s how I read it. Since most of the complaints on the forum are about compiler errors, when you say “broken”, that’s where my mind jumps to. I didn’t even consider that there might be a logic issue. So my bad, really, rather than yours :smiley:

:smile: I’m trying to figure out all the programming lingo - because I take programming really seriously because I want to be a professional iOS Developer. :+1:
I love it so much, I can code all day.
This site is incredible! I learn from the books & then have the ability to learn more from the author. It’s unreal.
Thanks again for your help! :slight_smile:
Rebecca

@fahim , You mentioned you were currently updating the book.

I’m on Chapter 27 section Generate the Code page 624 in 6th edition.

In my version of Xcode Version 9.4.1 (9F2000)
Location+CoreDataProperties.swift explicitly declares the access level public modifier in it’s @NSManaged property declarations.

Not a big deal, but it left me wondering if you deleted the public modifier deliberately, I’m assuming it’s an Xcode version difference.

Book Screen Shot
image

My Xcode Screen Shot
image


Also…

Chapter 27 Saving Locations
Pass the context Page 628

In the example of Coupled Code (what not to do):

let appDelegate = UIApplication.sharedApplication().delegate
                                             as! AppDelegate 
let context = appDelegate.managedObjectContext

Xcode made me use shared instead of sharedApplication()

image
Fixing that gives me:
image

let appDelegate = UIApplication.shared.delegate as! AppDelegate


That’s all I have so far in Chapter 27

Yes, that’s an Xcode version difference :slight_smile: If any changes are made to the generated code, I do mention it in the book.

Actually it still doesn’t work completely. While you have the section and row logic right, it doesn’t behave the same way when indexPath is nil.
The first two versions call resignFirstResponder() when indexPath is nil; this one (and the original 3rd version in the book) do not.
You can test this by tapping on a section header, which is not a row, causing indexPath to be nil. It is desirable to resignFirstResponder() on any tap that is not in section 0 - row 0, not just the taps in another row.
Your guard statement version does do the right thing with a nil indexPath.

Steve! - my functional programming sensei (先生)! :wave::grinning:

I tapped on a section header like you suggested to test (awesome info btw!), and this worked

    if let indexPath = indexPath, !(indexPath.section == 0 &&
      indexPath.row == 0) {
      descriptionTextView.resignFirstResponder()
    } else {
      descriptionTextView.resignFirstResponder()
    }

The downside is that whenever you are in the textfield and tap outside of it onto the cell itself, the keyboard flickers (gross)
I’m assuming it’s because it starts to resign and finds the logic is true so it brings up a new keyboard super fast?

Cheers!
Rebecca

That version resigns in both branches of the If…Else, so it always resigns. The flicker is a new one coming back if you are in the text box.
I checked, and some of the Apple apps only resign when a different row is tapped, not for taps that aren’t in a row at all. So you can do it either way, according to taste. But it should be the same in all three versions in the book, whichever way it goes. It is all too easy to think something is logically equivalent when it isn’t for a particular case.

Here is my favorite version, because it comes closest to saying what you really mean:

if indexPath == nil || indexPath != IndexPath(row: 0, section: 0) {
  descriptionTextView.resignFirstResponder()
}
1 Like

This topic was automatically closed after 166 days. New replies are no longer allowed.