Swift Struct All The Things

Should Swift Presenters Be Classes or Structs?

Swift structs aka Swift structures came into being and there was much excitement. Members of my own team back then were leaning heavily towards the idea of structs everywhere. As shared in Swift Protocols With Associated Types – PATs, “We were going to use structs and protocols wherever we could.”

Swift Struct All The Things

Should Struct All The Things?

The excitement is over, the dust has settled, and lessons have been learned. Now the question has been raised, should Presenters be classes or structs?

Stack Overflow Discussion and Unfortunate Answer Bias

Titled Why Choose Struct Over Class?, this Stack Overflow post’s chosen answer has been subtly framed in a way that reflects that initial excitement of leaning heavily towards creating Swift structs. It’s framed as if there is a contradiction between the WWDC 2015 talk Protocol Oriented Programming in Swift and Swift Programming Language documentation.

Based on what I and others can tell, there’s no contradiction. Also, the final line in the accepted answer is under scrutiny. Here’s the line under scrutiny:

Also, keep in mind that these concepts are always evolving and The Swift Programming Language documentation was written before the Protocol Oriented Programming talk was given.

As Dan Rosenstark rightfully pointed out:

Last line should say, “My personal advice is the opposite of the documentation:”… and then it’s a great answer!

That said, the content in the accepted answer copied from various sources is good and the post has had a lot of great interaction in it. This content and the Apple sources referenced clearly show when to use a class and when to use a struct.

Architecture

First, let’s get something out of the way right away. Are our Presenters really Presenters in our CARFAX app architecture? As shared in A Hungry Reflection on “How to Isolate Client-Server Interaction Logic in iOS Applications”, there’s often a debate as to whether we’re set up more for a Model-view-presenter (MVP) architecture, versus Model View ViewModel (MVVM) architecture, versus a Presentation Model architecture. This kind of discussion has gone on for over a decade. Regardless of where you land in the debate, the things that hold our display logic are known as Presenters. For the purposes of this blog post, let’s call them Presenters.

Presenters – Class or Struct?

Presenters contain display logic. There is one instance of them created and they are hooked up to the View Controller classes. Their purpose in life is to contain display logic that is unit testable and help keep the View Controllers from being too big.

Copying or comparing instances of the presenters doesn’t make sense. Presenters don’t fall anywhere near the “Examples of good candidates for structures” list in the section titled “Choosing Between Classes and Structures” of the Swift documentation’s Classes and Structures page. The same is true for the “Classes and Structures” section of The Official raywenderlich.com Swift Style Guide which is a favorite of many teams.

Conclusion

Structs are awesome to use when passing around simple value objects, whose properties are value types, and are meant to be compared and/or copied. To use structs in other situations is an understandable mistake. In hindsight, our own team tried to make some things structs that should have been classes from the beginning. We fell slightly into the Golden Hammer Anti-Pattern trap. Using a struct for a Presenter or other things like Presenters isn’t upholding the semantic differences between a Swift struct and a Swift class.

Update: Added reference to the “Classes and Structures” section of The Official raywenderlich.com Swift Style Guide

Pretty candle balls sparkling in the snow

How Big Is The Ball of Wax For Quality Assurance?

At CARFAX, we have awesome Quality Assurance (QA) support for the CARFAX iOS app and other apps. In order to do an awesome job, QA needs adequate time to do adequate regression testing before the next release of an app. The question is how much time is needed?

I like to think about this in terms of balls of wax. Amongst other things, the total effort of a project includes both an amount of coding plus a certain amount of testing. Therefore, the coding-ball-of-wax plus the testing-ball-of-wax equals the whole ball-of-wax.

In order to give QA a feel for how long it will take to regression test at the end of a project, they need some data. One idea that I’ve heard a few times is to use Story Points. What Are Story Points?

As I put it once, Story Points are how much brain-power plus actual coding is required to make the change. Do Story Points help give QA a feel for how much functionality change is being introduced? Not always.

A Story Point size is reflective of how much effort a developer has to put into making the change. It’s not reflective of how much testing is needed for that specifically changed feature.

How can we give QA the data they need in order for them to size the amount of QA work? If one feeds into the process, a “Feature Change Amount“ that will give them the information they need. The Feature Change Amount could be sized the same way as Story Points are sized. As opposed to Story Points however, a Feature Change Amount directly reflects something useful by QA so they know how much QAing is needed.

How does your QA get a feel for how long it takes to QA a project before it’s released for your customers to use? Feel free to share it with me on Twitter!

Pretty candle balls sparkling in the snow

CARROT iPhone App Video Marketing Done Right

The maker of the CARROT TODO app does user experience and marketing right in so many ways. To keep this post short, let’s just focus on one bit of video marketing titled CARROT Launch Trailer. The video is fun enough that I even saved it to watch again!

The video starts with some exciting music and a strong message similar to this: “the todo list with a personality.” It’s a good clear message which shows how it distinguishes itself and what the app does.

With the blue circle pulsing, the video moves on to the playful and humorous statements of “Let’s play a game. We’ll call it ‘Don’t Suck at Life.'” It shows some functionality of the app and then moves on to the rules of the game. Get stuff done or CARROT will get mad!

As someone who has used the app for years, I guarantee she (CARROT) will get mad. CARROT is often referred to as the user’s “new mistress.” Here’s the video:

One thing the video doesn’t show you is the funny and sometimes creepy (in a humorous way) push notifications that the app receives. I highly encourage you to turn the notifications on. Although the humor is often dark, it is fantastically funny. Check out the app for yourself!

Communities in Nonsocial Mobile Apps

Nonsocial apps with a social community inside of them. It seems to make sense since you already have a captive audience. However, does it always make sense? Let’s first dive into mobile apps that come with communities.

Besides the obvious social mobile apps, there are multiple apps with communities aka groups inside of them. These apps are not primarily social apps, but they attempt to support a community. Since humans are social beings, it can be a nice feature which can make the app more appealing and thus used more often.

Some Community Supporting Apps:

  • Argus – It’s a highly social activity tracker app that has a groups section. There’s more on Argus further down in this article. iPhone and Android apps exist.
  • Coursera has a “Discussions” area in the iPhone app. There’s an Android app too. Discussions are not available until a course starts. So, one cannot peek inside right away and explore it.
  • Lose It! – Weight Loss Program and Calorie Counter – Has a “Social” section with many groups in it. The group activity in it is kind of strong. Strongest are the groups which are promoted as “Featured Groups”. iPhone app and Android app exist.
  • Not quite a discussions area, but Udemy has a Q & A section which has questions directed at the instructor in a particular instructor. This provides longterm value with credibility in the information since the answers come from the instructor. However, there is no sense of community. They offer an iPhone app and an Android app.
  • It’s worth noting that I have seen apps drop support for groups. That can sometimes be the smartest move.

More on Argus

The target audience of the app focuses on people who like to be social while tracking health, fitness, meditation, sleep and other trackable activities. Even though the semi-new groups section is pretty dead, there’s a novel tie in from a group into the tracked activities of group members which I find interesting.

It’s interesting in how it provides a kind of newsfeed style of tracked activities. You can tap on a button in the group and see a combined newsfeed from the group members. Compared to the messages button, this has much more activity. Unfortunately, most of the activities have nothing to do with the particular group you are in since they are not filtered. At a glance, it’s also a slightly confusing user experience.

Also, the downside of the groups section is that it’s slow to load and has an annoying bug which makes the iPhone app crash when you click on a link. As a side note, I happen to run a meditation group in Argus that has 25 members.

All that said, it’s worth a look. The groups has potential if a few things are tweaked, promoted, and fixed.

Externally Support the Community?

Should one just tie into an existing social app such as Facebook to support a community? It’s a fair question. Facebook has a groups feature which can be successful. The most successful Facebook group I have been a part of is the Octalysis Explorers. It has over 2000 members. Like any group, a lot of effort goes into keeping the community engaged. Fortunately for the Octalysis Explorers, Yu-kai Chou is a master at the art and science of engagement. He has a handful of awesome and loyal people who support the effort.

The people supporting the Octalysis Explorers group are continuously driving people to the Facebook group through multiple channels. Even in its own “Join the Movement” section, the group is highlighted in Yu-kai Chou’s great book titled Actionable Gamification – Beyond Points, Badges, and Leaderboards. There are also multiple administrators for the group. Also, there is always at least one person actively interacting with every post. A successful community relies on that kind of wonderful support from its administrators and its members.

Summary

Even though the implementation and user experience is pretty rough, it seems like the app with the most group activity without overt support is “Lose It!” However, that’s not saying much. The app with the most potential from a technology point of view may be Argus. However, Argus is already a highly social app so its group feature doesn’t add much.

If one can dedicate people to supporting a community on Facebook, that might be your best bet. If you go that route, you will need to continuously drive people to the group through your existing email marketing, verbal announcements in events or podcasts, and every other chance you get. Communities require care and feeding.

No matter how you support a community experience, it can provide an advantage over other solutions who don’t provide such. If one cannot dedicate the resources to the community experience or if the community experience doesn’t ever pay off, my advice is to drop it and refocus on other things.

iOS Color War! Appearance Proxy vs UIButton Title Text Color

Now here’s a weird issue that appeared in iOS 10, I found myself saying one day. I was seeing an iOS button’s title change color as a I navigated from one scene to the next. It got worse. When I navigated back, the button’s title color stayed the wrong color. It was the same color as all the labels in the iOS app. What’s going on?

We dug in deeper and discovered something. There was a nasty appearance proxy color issue where the appearance proxy would change the color of the UIButton‘s title text color even though the code was explicitly setting the color. In fact, the appearance proxy would set it to be the same color as it has configured for all UILabel objects. The configuration code for labels was like this:

UILabel.appearance().textColor = labelTextColor()

Since a UIButton contains a UILabel, that might make sense. How does one fix this situation?

The answer to fixing it was discovered after thinking about what was read in this Stack Overflow post titled Appearance Proxy overridden when resetting text:

iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window.

It turns out the code to explicitly set the color on the UIButton was getting called before the view appeared on the screen aka viewWillAppear. Once the view appeared on the screen, the appearance proxy would set the button’s label’s text color aka button title color.

As a side note, this only seemed to happen when using setAttributedTitle on the button as opposed to calling setTitleColor and setTitle separately. Unfortunately, we wanted different parts of the text to be different sizes. So, using setAttributedTitle still seemed like the thing we should do.

Given all that knowledge, we called setNeedsLayout on the UIButton in viewWillAppear and viewWillDisappear That fixed everything up! The button no longer appeared to change color when switching between screens. Hurrah!

 

 

Adding Swift Initializers Through Extensions

While watching the Stack Views with Enums by objc.io, I learned an interesting little tidbit. You can add a convenience constructor aka convenience initializer by extending a class. The benefit of doing such is that you don’t have to subclass the class. In hindsight, the availability of that feature seems obvious. The Swift reference even has a section called “Initializers”. However, this ability may be news to others as well.

Similar to what they show at 7:45 in the video, one can write the following:

Next, you can call this new init like any other initializer:

I highly recommend you watch the entire Stack Views with Enums video. Enjoy!

RxSwift and Squishing the Pyramid of Doom

Say, you just learned RxSwift and all about subscribeNext. You have a series of Harry Potter related service calls to make and they affect each other. Let’s also say they all return the same type of Observable<Person>. So, you start to call these services one after another using subscribeNext.

The indention of calls is known as the Pyramid of Doom. This is a case of not using all of the power that RxSwift offers. If we inject flatMapLatest into the mix instead of all subscribeNext calls, we get the following:

Not only is the flatMapLatest approach easier to read, but one can see easily where the addDisposableTo(disposeBag) should be added at the end to manage the memory.

This concept is also covered in the RxSwift Tips document. Enjoy all that RxSwift has to offer!

Swizzle Swift Class Methods

While writing some test Swift code, I ran into a situation where I wanted the implementation of a class method swapped out with some fake code. Basically, I wanted to swap out SomeClass‘s saveSomeThings class method with a fake one.

Inspired by NSHipster’s Swift & the Objective-C Runtime article, I came up with some concise code that does what I want. Focusing on only what shows the concept, we have the following example SomeClass:

The saveSomeThings method implementation is what we want to swap out with some fake code for testing purposes. How, you might ask? First, ensure the method has the dynamic keyword as discussed in this Stack Overflow post. Next, we grab a handle to the class method like so:

Now we need something to swap it with. What if we had a method inside a SomeTestClass class like the following just for testing purposes?:

We can grab a handle to the method like so:

The actual call to swap the implementation between the saveSomeThings and forTesting_SaveSomeThings is done using method_exchangeImplementations like this:

The SomeTestClass prefixes the originalMethod and swizzledMethod because I am storing them as static members of the SomeTestClass.

Those are all the magical pieces of this puzzle! Besides being on github, here is a complete Swift playground example to see it all in context:

At CARFAX, I have been fortunate enough to work on such interesting challenges like the one above in Swift, Objective-C and Java based languages. Since CARFAX is a growing company with opportunities that open up from time to time, you might want to checkout the CARFAX Career link.

Regardless, I hope you found the above information interesting and useful. Enjoy!

Hit Your Own Server On Your Mac With Your iPhone

To truly evaluate the user experience, there is no substitute for having the app on your iPhone and in your hands. Yet, it’s rare that a person can make an iPhone app that doesn’t depend on a server of some kind.

If you don’t have a server deployed somewhere yet, what can one do? Well, you can hardcode values in the app. However, that can be more trouble than it’s worth. Also, you’re not testing the whole app end to end. So, what one can do is create a mock server that returns hardcoded values using Node.js or some other framework. Great!

Just one thing, the mock server your iPhone depends on is not ready to be deployed. It’s on your machine only. What to do?

You can run the server locally on your mac and have your iPhone hit it over wireless. Sounds easy enough. Right?

After figuring out your IP address of your machine for the phone to hit, changing the iPhone app to hit whatever URL it needs, and probably temporarily turning off App Transport Security so you can hit it with an http as opposed to an https URL, you may find that your iPhone app still cannot hit the machine your mock server is running on.

Stack Overflow to the rescue! After digging into the google world, I found the key sentence I was looking for in a Stack Overflow post:

I turned off my WI-FI on my Mac and then turned it on again, which solved the problem.

Although I’m not positive, it seems like I had to flip the wireless from on to off and back to on more than once. To test that the phone can reach the machine, I used safari on the iPhone to check that I can hit anything at all on that machine.

Once I figured all this out, I was so happy that I decided to write this for others to use. If it wasn’t for Stack Overflow and our community of knowledge sharers, where would we be today?

Fire! Wife, Apple Watch, and Meditation are Heroes

Ring! Ring! There goes my Apple Watch. The iPhone is in another room and my hands are dirty-dishes-gross. “That’s weird and annoying”, I think reflexively to myself. My wife is calling but she just left.

With the final ring sounding, I quickly do the right thing regardless of my thoughts. I rinse off a pinky finger and answer the call on my Apple Watch with it. I hear her Apple Watch’ed voice say loudly “Get a trashcan full of water and …. <something about a bin>.” What’d she say? After quickly rinsing off my hands, I grab a trashcan, yank the trash out, and mutter about needing caffeine while filling it up with water.

Next, I’m outside. Hmm! Lots of smoke is coming from the trash bin area. Uh oh… A quick emotion check reveals slight concern and the thought that I better get out there soon and see what’s up. I’m slightly surprised about how matter-of-fact my mind feels.

Keeping a clear mind is a credit to the meditation training I’ve done over my life and most recently received from my two favorite meditation apps. At some point, I run toward the smoke and check out the situation. Oh! This fire could spread quickly!

My wife had emptied the wastebasket full of water and tells me to get the fire extinguisher. “Good thinking”, I reflect while running back. I dug it out from the back of the closet, run it out to her, and she puts the fire out while I am running back for more water. Success!

A photo of the inside trash bin area that caught fire.

Where the Fire Started Inside the Bin Area

Just then, the maintenance person shows up that my wife had called. Good. He can do any needed follow up with whomever.

Fire scorched trash bin area fence

Fire Scorched Fence Outside of the Bin Area

Let’s recap. The trash bin area is completely surrounded by a dry timber fence. If I hadn’t been wearing my Apple Watch, had my meditation training, and/or my hero wife hadn’t seen the fire, it might have gone completely up in flames. As my wise wife said, who knows if a floating fire ember would have started another fire on a nearby home?

As far as who the hero is that kept people and property safe, the credit goes to my wife.

This is also a moment of gratefulness. I am grateful for my wife’s levelheadedness. I’m also thankful to Apple for their innovation and specifically my Apple Watch. Finally, I feel lucky to have experienced first hand the fruit of all of my meditation training which kept the whole event in perspective and kept me from overreacting.

May you also be as blessed as me in such times!