Determining the current state of a UITableViewCell

http://stackoverflow.com/questions/12433330/determining-the-current-state-of-a-cell

extension UITableViewCell {
    var currentCellState:UITableViewCellStateMask {
        get {
            if (self.isEditing && !self.showingDeleteConfirmation) {
                return .showingEditControlMask
            } else if (!self.isEditing && self.showingDeleteConfirmation) {
                return .showingDeleteConfirmationMask
            } else if (self.isEditing && self.showingDeleteConfirmation) {
                return [.showingEditControlMask, .showingDeleteConfirmationMask]
            } else {
                return []
            }
        }
    }
}
Advertisements

Helpers in XCTest

Extracting asserts into my own helper assert methods I realized when the tests would fail, they’d fail inside those methods and the failures were providing no hints as to where the failing test actually called the helper methods.

Then I ran across this awesome blog post where it describes XCTest’s method

recordFailure(withDescription:inFile:atLine:expected))

Now of course the question would be: where do we get the “file” and “line” params from? Well, it turns out Swift offers the compiler macros “#file” and “#line” and we can use those as parameter defaults. So for example:

 

func assertTitles(_ titles:[String], inSection s:Int,
                  file:String = #file, line:UInt = #line) {

	...
}

 

Beautiful.

Separate UserDefaults for Unit Tests

Some of the components I’m trying to test use UserDefaults.standard for storing user preferences…unit testing these components has been a pain when trying to reset UserDefaults.

Instead, I’m now centralizing all instances of UserDefaults.standard which is then replaceable by the unit test. My test can then call:

testDefaults = UserDefaults(suiteName: "UnitTests")

and inject these defaults into the component I’m testing. In the teardown method, I then simply call:

testDefaults.removePersistentDomain(forName: “com.myapp.Identifier")

As often, found on StackOverflow.

Revealing a button in a custom UITableViewCell when transitioning to editing mode

I wanted to have my UITableViewCell smoothly reveal a “hide” button next to the “delete” button when the table view is in editing mode, indenting the text labels to the right of it.

First step was to subclass UITableViewCell and then override its method willTransition(to state:).

I linked in the left border constraint and animated the text elements over to the right of the new hide button.

But even when animating the button and text elements with UIView.animate(withDuration:animations:), the changes would appear right away instead of being animated along with the transition.

So the second step was to put the animating code into its own async call. Now it animates nicely.

override func willTransition(to state: UITableViewCellStateMask) {
        super.willTransition(to: state)
        DispatchQueue.main.async {
            if (state.contains(.showingEditControlMask) ) {
                self.hideButton.isHidden = false
                self.hideButton.alpha = 0
                self.leftMarginConstraint.constant = 40
                UIView.animate(withDuration: 0.5) {
                    self.hideButton.alpha = 1
                    self.layoutIfNeeded()
                }
            } else {
                self.hideButton.alpha = 1
                self.leftMarginConstraint.constant = 0
                UIView.animate(withDuration: 0.5, animations: {
                    self.hideButton.alpha = 0
                    self.layoutIfNeeded()
                    }, completion: {
                        _ in
                        self.hideButton.isHidden = true
                })
            }
        }
    }

Cannot assign to property: function call returns immutable value

struct Section {
	var elements:[Elements]
	...
}
…
func section() -> Section {
	...
}
…
section().elements = newElements  // <- error

Had a struct which a method was returning, but was unable to immediately set a property on it because methods return constants by default.

First thought (via StackOverflow): first store the return value in a var, then assign the property.

var section = section()
section.elements = newElements      // <- this "works"!

However – remember that the method is returning a copy of the struct, so all this does is set the elements field on the copy.

In my case, it made far more sense to turn the struct into a class, since I didn’t want copies of my Section but rather a full reference.

“Setting the background color on UITableViewHeaderFooterView has been deprecated. Please use contentView.backgroundColor instead”

Kept getting this message when I created my own custom UITableViewHeaderFooterView, even though I wasn’t setting a background color in my code anywhere. Needed to do the following to fix it:

  • Remove the background color from the .xib’s main background color
  • Put in a top-level view in the .xib, give IT the background color I wanted
  • As found here, implement contentView to return that top-level view