Scroll to top in iOS 13 UI Testing

In XCTestCase if you want to scroll to the top of a scrollable view, you tap on the status bar

XCUIApplication().statusBars.firstMatch.tap()

However, this is doesn’t work in iOS 13.

I filed a radar during the beta and they just got back to me with this.

The status bar is no longer part of the application, it’s part of the system UI (“springboard”). Change your test as follows:

let systemApp = XCUIApplication(bundleIdentifier: "com.apple.springboard")
systemApp.statusBars.firstMatch.tap()

This seems like it should be important, but it was not documented anywhere on Apple’s website.

If still need to support Xcode 10 / iOS 12, I recommend using the following extension

extension XCUIElement {
    func scrollToTop() {
        if #available(iOS 13, *) {
            let systemApp = XCUIApplication(bundleIdentifier: "com.apple.springboard")
            systemApp.statusBars.firstMatch.tap()
        } else {
            XCUIApplication().statusBars.firstMatch.tap()
        }
    }
}

I figured I would share this so that it is at least documented somewhere.


Tips for Great Conference Calls

Working in software development, is it guaranteed that you will attend a conference call at some point. I hate to use the cliché, but it’s 2019 and some people are still terrible at this. You will hear noises in the background, people won’t pay attention or will talk over each other and you have technical blunders.

So I decided to put together a list of tips for improving your conference call experience.

Find a good meeting space

This one sounds obvious, but try to make every effort to obtain a quiet space to have your meeting. Conference rooms are the best choice, but barring that, any quiet space will do.

Also be aware that while it may be quiet for you, you will be potentially making the space less quiet for other people. Avoid taking calls at your desk if you are in an open office.

If it is nice outside and you are the only caller from your end, it can sometimes be nice to go for a walk. I have taken calls on city walking trails and parking garages before. This might not be ideal for every call, but it’s a good option to have.

Join on time

When you schedule a meeting, you are making a promise to your attendees, you are taking up peoples time. if you fail to join people who could otherwise be doing useful work are instead waiting in dead silence for the call to begin.

Don’t be late.

If you absolutely must be late, make sure you send out a notification as early as possible to let them know of your delay or, even better, update the calendar invite with a new start time.

Sound

If you are taking the call alone, use headphones with a microphone. These typically sound better because the microphone is close to your mouth, but be mindful you don’t move around much if it is laying against your shirt. Avoid Bluetooth headphones unless you know they are of a high quality so you don’t sound robotic.

Mute yourself when you are not speaking. Learn how to mute your call in the software you use and make liberal use of that button.

If you are taking a call with multiple people, avoid using Laptop microphones. Also, be aware they can pick up the sound of every keystroke if you are typing while talking. We have a couple Jabra Speak 510’s in our office, and they work great.

Make sure you silence your phone and laptop.

I like to do a quick audio and camera check before I join a call, most conferencing software will have a screen for this in their settings. Check your Mic and Camera to make sure the correct devices are selected.

Pay Attention

If you aren’t presenting or on camera, it can be easy to pull out your phone and browse Reddit or stare blankly out a window, but try to pay attention having to ask “wait, what did you say again” can be embarrassing.

Put your devices in Do Not Disturb mode so you don’t get sidetracked by text messages or other notifications. iOS has a great feature where your phone will remain silenced until the end of your current calendar item.

For meeting hosts, try to stay on topic and keep people involved in the conversation, this will prevent wandering minds.

If you find a meeting has become sidetracked and the main topic is complete, please don’t hesitate to let people uninvolved in the side topic know they are free drop off.

Keep your desktop clean

If you are going to be sharing your screen, make sure your desktop is not cluttered. Take special care to remove documents with confidential or private information. Remove that funny meme your friend sent you. Just make sure your desktop has nothing that will embarrass you or your company. To make it easier, you can just make a folder called “clutter” and move everything in there.

I’ve already mentioned Do Not Disturb mode several times in this post, but if you are screen sharing and you get an inappropriate text message from a friend, you will regret not silencing your notifications.

Do a camera check before joining video calls

Before you join the meeting fire up your camera and take a look at your background.

Check for clutter. Dirty laundry, trash, alcohol bottles… I have seen all of this, and it’s just unprofessional.

Make sure you don’t have proprietary information up on a whiteboard. If you do client work, this is especially important as it can have legal ramifications.

Check yourself. Look in the mirror, make sure you are as presentable as you would be in person.

Open Questions

Try to avoid asking undirected questions, try to keep them directed at individuals. Asking questions like these will cause one of three things to happen.

  1. Multiple people answer at the same time and they talk over each other
  2. No one talks and you get dead air and have to direct your question at a specific person anyways.
  3. What you want to happen, happens and the correct person and only that person answers.

You get a 1/3 chance for it to work, It’s awkward and you should just avoid it if possible.

If you are running a standup meeting, you get to pick who talks first, don’t open it up to the floor.

In Summary

  • Find a quiet place that won’t bother other people.
  • Be punctual or notify everyone you will be late as soon as possible.
  • Take measures to prevent interrupting sounds.
  • Pay attention so people don’t have to repeat themselves.
  • Check your desktop before enabling screen sharing.
  • Check your environment before joining a video call.
  • Avoid undirected questions.

I hope you found this useful and if you didn’t, great job, you were probably already doing the right thing.

Please share this and perhaps we can make conference calling better for everyone.



The Trap of Libraries

One of the worst feelings I can ever have in iOS Software Engineering is cloning an existing project for the first time and looking at the Podfile. I feel it gives me a good sense of how the project is going to go. If there are only 1 or 2 pods, I sigh a breath of relief, if there are more, I start the mourning process.

It’s not like having a handful of pods are always a bad thing, but most of the time they definitely are.

Here is a short list of things that I don’t mind seeing in a Podfile.

  • HockeyApp
  • Fabric
  • Google Analytics
  • Urban Airship

Libraries like these are helpful, they integrate backend services that might be overwhelming to create from scratch, and allow you to focus more on your app. While they tend to be a little larger than one would like, the companies that maintain them tend to spend time making sure they are low impact, relatively bug-free, and fairly easy to keep updated.

Here is a list of libraries that send a chill down my spine.

  • ReactiveCocoa
  • Mantle
  • AFNetworking
  • Facebook Pop
  • ZXingObjC

There are many more I could list here, but let’s get to the point. These libraries are a loan from the bank of tech debt. Using some of these commits large portions of your code to require constant maintenance, and you can only avoid it for so long.

The First Problem

When I tell people my thoughts on these libraries, they always tell me…

They are open source, if there is something you don’t like you can always just fix it.

or

If the maintainer goes away or stops supporting it, you can take it up.

Let’s run a little thought experiment on this, shall we?

Take AFNetworking for example…

If I am building a library that uses Apple’s URLSession to build my network stack, I can be fairly confident that it will be maintained as long as the platform is. It has a lot of features, is relatively bug-free, and I don’t have to pour over its source-code with every update to make sure it is following the new best practices.

However, if I use AFNetworking, I potentially have to wait weeks before new language, security, and platform features are integrated. I am not sure if you remember the certificate pinning issue, but the gist of it is that the maintainers identified a security issue introduced in one of their patches and, to their credit, they patched it in about a week. The problem arose in that every developer who used the library didn’t follow the news, or had to wait for internal company processes to allow a release, then wait for Apple’s (at the time), slow, app review to patch this vulnerability. The effect of this was that over 1000 apps on the app store had this issue.

Now this is a big, frequently used library and the maintainers did the best they could to fix the problem as quickly and as loudly as they could, but can you say that you follow the git issues and blogs related to every single library you use? A small “syntactic sugar” library could easily introduce security issues without your knowing, and if it’s not used by A LOT of people, it will fly completely under your radar (I will avoid the obvious pun here).

And what if this library wasn’t even well maintained?

Yes, you could fork the library and start maintaining it yourself, but do you think your clients and managers will agree that spending several hours a week maintaining a library is a good thing? How would they feel if you are only using a couple functions? If they are ok with it, you probably have a great job with very understanding colleagues and you are probably on retainer, or work in a big corporation. Consulting/Agency work doesn’t usually afford this luxury.

Even if you only use popular, well-maintained libraries, you can still be hit by…

The Second Problem

In the beginning of this article, I talked about the dread I feel opening up an existing project’s Podfile for the first time, the worst thing you can see is at the top.

platform :ios, '6.0'

This means one or two of the following.

  1. This project hasn’t been updated in a LONG time.
  2. This project relies on a library that no longer exists.

If the issue is the former, you will probably have well over 100 random deprecated API warnings, and if you are lucky, only a couple hard errors. If it is the latter, get prepared to spend a lot of time extracting that pod from the application.

For example, I am looking forward to having to spend quite a few hours extracting Mantle from an application because the app heavily relies on a feature no longer present. This is not even close to the first time I have had to deal with this. Smaller libraries are a bit more loose with redefining their entire API in an update, completely breaking the hosting app, and sometimes introducing new bugs that can take weeks of updating to work out.

It can also be easy for someone working on the project to work around issues and never actually update the library. When it finally comes time that you do run pod update, you might find that you now have a week or more of fixes to get the new library running. Maybe you are the good guy (or gal) who spends time keeping pods updated and therefore you don’t have to waste weeks doing the epic rewrite, if you are this person, would you like a job?

Libraries can be useful when a task is too complicated or requires large amounts of infrastructure, but what I see a lot of the time are tiny, single-purpose, libraries that only marginally improve the workflow.

This sort of library can also dictate your entire architecture. They can lock you into something that might be trendy now, but in a year or two, you find yourself scratching your head and wondering how you ever got into this mess in the first place.

The Solution

If you are using a smaller library, why not write it yourself? Autolayout DSL’s, JSON parsers, custom animations; these aren’t generally very complicated to do on your own and since you wrote it, you should be able to easily fix it when needed. It will reduce app bloat, improve security, and you will get better at the problems these libraries solve.

Reducing boilerplate and simplifying common programming tasks are the siren songs of software engineering, they can be quite attractive, and it is easy to add them to your project. In reality, for larger projects, they are traps that lock you into spending quite a lot of your time putting out the fires they can create.

If you want my opinion, they are best avoided when possible.

Afterthoughts

It was not my intent to spend so much time picking on AFNetworking, it just provided a good example for issues I will encounter. AFNetworking was incredibly useful back before NSURLSession was a thin, but it is so easy to do it right with just foundation libraries these days, I wonder why it is still so popular for simple networking tasks. If you know why, please tweet at me.


Auto-Completion And Organization for NotificationCenter

I may be late to the party, but I just discovered the most amazing trick thanks to this article.

Have you seen this before?

NotificationCenter.default.post(name: NSNotification.Name(rawValue: "didSomething"), object: nil)

… yea, its pretty ugly, not to mention incredibly error prone. If you have to use this same notification in multiple parts of your app, you are very likely to typo that string literal at some point.

But, I just discovered some syntax sugar to help clean that up.

extension NSNotification.Name {
    static let appDidSomething = NSNotification.Name(rawValue: "didSomething")
}

With that in place, you can start adjusting your call-sites like this.

NotificationCenter.default.post(name: .appDidSomething, object: nil)

How glorious is that?

In retrospect, it seems a bit obvious, but the best tricks usually are.