Author Archives: Rex

iOS 12 Siri Shortcuts

The latest update (v1.3.6) of my iPhone app, Power Focus, passed app review today! The App Store review turnaround is amazing nowadays. Super quick.

My app includes minimal iOS 12 Siri Shortcuts support. Watching the WWDC session, there’s two ways to add Siri Shortcuts support: NSUserActivity & Intents. I went with the former since I didn’t need custom Siri UI.

Of different online resources, Anton’s medium post was really helpful as it covers the essentials of using NSUserActivity. With NSUserActivity, the important parts are donating Shortcuts during app usage and handling them in your App Delegate. That’s it.

The experience of implementing minimal iOS 12 Siri Shortcuts was painless and I would recommend your app using NSUserActivity to inform iOS when key actions occur.

Using SVG / PDF assets in your iOS app

This guide covers a simple way to use SVG (Scalable Vector Graphics) assets in your iOS app. This was tested on macOS High Sierra 10.13 with Xcode 9.4 and Swift 4.

There are many websites where you can find SVG icons. Check out Material or ionicons

  1. Install homebrew & python3 for macOS (if you don’t have it)
  2. Install cairosvg. The code below installs various dependencies
    brew install python3 cairo pango gdk-pixbuf libffi
    
    pip3 install cairosvg
  3. Convert your SVG icons to PDF files. Make sure to navigate to the location of your SVG icon files. Run this command for each icon file (with the relevant *.svg & *.pdf input / output file name):
    cairosvg icon.svg -o icon.pdf
  4. Drag your PDF files into your Xcode Assets.xcassets folder
  5. Adjust the settings for each icon in your xcassets. You may want to adjust:
    1. Name – this is important as you will refer to this in your Swift code to use the icon
    2. Set ‘Render As’ to ‘Template Image’
    3. Check the box for ‘Resizing – Preserve Vector Data’
    4. Set ‘Scales’ to ‘Single Scale’
  6. Use your icon in your app. I did this programmatically in Swift, and this works in your ViewController. Make sure to update the ‘iconName’ to match what is in your xcassets for your icon file.
    if let icon = UIImage(named: "iconName") {
        let image = UIImageView(image: icon)
        image.translatesAutoresizingMaskIntoConstraints = false
        image.tintColor = UIColor.blue
        view.addSubview(image)
    
        NSLayoutConstraint.activate([
            image.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            image.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            image.widthAnchor.constraint(equalToConstant: 24),
            image.heightAnchor.constraint(equalToConstant: 24),
            ])
    }
  7.  That’s it. Your SVG file was converted to a PDF file, added into your Xcode assets, and called from your ViewController!

DJI Spark – First Impressions

I’m new to drones and picked up a DJI Spark Fly More Combo during Prime Day, where it was $50 off. The price before tax was $500. The combo includes the remote control, an extra battery, and more helpful accessories.

The Spark hardware is a marvel of engineering. It’s not that big, but it packs a lot of technology inside. I chose the Spark since I wanted something small & novice friendly. The operating noise is very loud for my taste, but it’s to be expected for current drones.

The setup experience to start using the drone was very confusing. After charging my batteries & the remote control, it took me a long time to understand how to pair & fly the Spark.

The key revelation is that the Spark drone and the remote control each have their own WiFi network. Depending on which way you want to fly (using phone or remote), you have to connect to the right WiFi network. The problem is that the WiFi network(s) don’t always show up.

I couldn’t find any Spark WiFi networks, so I had to hold the power button on my drone for 10 seconds to reset the drone’s WiFi. Then I could connect to the drone with my phone.

Despite being able to connect to my phone, I wanted to use my remote (instead of the phone’s virtual joysticks). This link about rebooting the remote helped fix my issue. With the remote WiFi to phone being so unreliable, I’ve gone and ordered a 3rd party Lightning to USB Cable.

The drone to phone or remote pairing process is very painful. The process involves pressing & holding various buttons on the drone or remote and waiting several seconds for different beeps & lights. It’s about as user unfriendly as you could get. There is potential for a firmware update or DJI GO 4 mobile app update that would help resolve some of these pain points, but I wouldn’t hold my breath.

Once you are able to pair the drone to the remote control (and pair your phone to the remote control), the flying part is fun. There’s a learning curve, but the remote control’s hardware joysticks make flying intuitive.

One other note, I’m currently residing in Los Angeles. LA is not drone friendly as there are many airports and restrictions. It’s very likely you can’t fly where you want to in LA. Definitely check out where you can fly drones in your area before purchasing a drone.

My Aging MacBook Situation

My personal daily driver is a 2011 MacBook Air (MBA). I’ve shipped 6 iPhone apps from it. For a computer bought in 2011, I’m happy with how long it has lasted.

I am interested in buying a new MacBook Pro (MBP) to replace my aging MacBook Air, but I’m not sure what to do. The possible choices I see are:

1.) the current MBP (June 2017 version)
2.) wait ? months for an updated MBP (most likely a minor CPU refresh)
3.) a 2015 MBP version (older hardware style with IMHO better keyboard)

Reasons to upgrade sooner:
* Xcode runs poorly on my MBA. Storyboard, Simulator, and Playgrounds are barely usable.
* macOS Mojave will not run on my MacBook Air. It’s only a matter of time before I’m locked out of macOS & Xcode updates.
* Apple announced a Keyboard Service Program.
* As a professional software developer, I can easily justify 2-3 year upgrade cycles.
* My MBA is showing it’s age; the battery is virtually gone.

Reasons to upgrade later:
* My MBA is able to run Xcode 9 (current) and will hopefully run Xcode 10 GM.
* Buying after a new hardware refresh (minor CPU bump most likely) maximizes the currentness of the purchase. This may not be rational, but it’s a factor nonetheless.
* My iPhone app development is primarily dependent on iPhone hardware updates & Xcode, not my Mac.
* Indecision – since none of the current MBP options (2015 or 2017) are very appealing, I can wait it out.

Reasons that don’t make a difference:
* I don’t like typing on the current generation MBP keyboard, but the next significant MBP hardware refresh is probably a few years away (too long).
* USB-C – I’ve found a Multi-Port Adapter (dongle) that works for me.

Inconclusion

In retrospect, I should have bought a decently equipped 2015 MBP in 2015.

If Xcode 10 GM doesn’t work on my Mac, then I’ll be forced to buy a new Mac right away. Otherwise I will wait around hoping Apple decides to update the MBP.

Git Config Email String

This is about a simple problem that is obvious after the fact. I was having an issue with my commits on github.com not being linked to my github account. It seemed like I had set everything up (git email configured locally & e-mail set in my github.com account), but it wasn’t working.

On a mac, you probably know you can set your git user e-mail this way:

git config --global user.email name@domain.com

Following the github guide (https://help.github.com/articles/setting-your-commit-email-address-in-git/), I included quotes when setting my git config email.

git config --global user.email "name@domain.com"

It turns out that was a mistake for me since my commits were being associated with “name@domain.com” instead of name@domain.com. Note: the inclusion vs exclusion of quote characters.

After running the git config command above without quotes, I was able to properly link my commits on github to my github user profile.

Intro to Computer Vision

I’m new to computer vision and a lot of the basic concepts are very interesting. As an iOS developer, my interests comes from using CoreML & Apple’s Vision in apps to improve the user experience.

Two common tasks are classification and object detection. Classification allows you to detect dominant objects present in an image. For example, classification can tell you that photo is probably of a car.

Object detection is much more difficult since it not only recognizes what objects are present, but also detects where they are in the image. This means that object detection can tell you that there is probably a car within these bounds of the image.

What’s important is that the machine learning model runs in an acceptable amount of time. Either asynchronous in the background or in real time. Apple provides a listing of sample models for classification at https://developer.apple.com/machine-learning/.

For real time object detection, TinyYOLO is an option, even if the frame rate is not near 60 fps today. Other real time detection models like YOLO or R-CNN are not going to provide a sufficient experience on mobile devices today.

One other interesting thing I came across is the PASCAL Visual Object Classes (VOC). These are common objects used for benchmarking object classification.

For 2012, the twenty object classes that have been selected were:

  • Person: person Animal: bird, cat, cow, dog, horse, sheep
  • Vehicle: aeroplane, bicycle, boat, bus, car, motorbike, train
  • Indoor: bottle, chair, dining table, potted plant, sofa, tv/monitor

These are common objects used to train classification models.

Computer vision used with machine learning has a tremendous amount of potential. Whether used with AR or other use cases, they can provide a compelling user experience beyond Not Hotdog.

Hoji Soft Serve

Recently, I had the pleasure of visiting Oahu for a short weekend trip. We were fortunate with perfect, sunny weather during our stay. We ate many things, and one thing we really enjoyed was Nana’s Green Tea.

Nana’s Green Tea is in the back of a Japanese food court, Waikiki Yokocho. Their menu is filled with drinks and desserts. The prices are not cheap at all, but the quality is decent. I’d recommend the soft serve or parfait desserts.

We tried both matcha soft serve & hoji soft serve. While everyone is familiar with Instagram-friendly matcha, we were introduced to hoji tea. Hoji is roasted tea that has a more subtle, darker flavor.

I think hoji soft serve could make it big as an Asian dessert. As someone who follows food news, I’ve never come across any hojicha coverage, but matcha is covered all the time. Hoji isn’t as Instagram-friendly (perhaps swirl it with matcha), but the flavor sells itself.

How to use child View Controllers in Swift 4.0 programmatically

I’ve just released my Learn to read Korean app for iPhone. It uses a number of child View Controllers in the home screen. While child View Controllers are not a new thing, it was a new experience for me, and I greatly recommend them to reduce the clutter of your View Controllers.

Here’s a photo of my home screen:

The main view controller consists of a vertical UIScrollView and multiple horizontal scrolling UICollectionViews below. While it’s possible to do it all in one massive View Controller, it’s much better to delegate UICollectionView events to their individual child View Controllers.

The good news is that using child UIViewControllers is super easy. You can use your Storyboard or do it programmatically in your UIViewController files. I opted for the latter as I find it easier to reproduce across Xcode projects.

All you need to do to add a child View Controller is below. I included an optional constraints section.

// Create child VC
let childVC = UIViewController()

// Set child VC
self.addChildViewController(childVC)

// Add child VC's view to parent
self.view.addSubview(childVC.view)

// Register child VC
childVC.didMove(toParentViewController: self)

// Setup constraints for layout
childVC.view.translatesAutoresizingMaskIntoConstraints = false
childVC.view.topAnchor.constraint(equalTo: heroView.bottomAnchor).isActive = true
childVC.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
childVC.view.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
childVC.view.heightAnchor.constraint(equalToConstant: height).isActive = true

With multiple child VCs (each handling their own UICollectionView events), the code base becomes manageable. In each child View Controller, you can handle customization, such as background color, UILabels, UIButtons, etc.

Another tip I have is to use the UIView’s convert(_:to:) method as necessary. You may need to get the child subview’s position relative to your parent View Controller’s view (such as for an UIViewControllerTransitioningDelegate). The code for that is simple too:

// contrived example label in Child VC to get parent frame
let label = UILabel()
let childViewFrame = label.frame
let frameInParent = label.convert(childViewFrame, to: parentVC.view)

That’s all I wanted to share for today. Don’t be afraid of using child View Controllers to break up your massive View Controllers!

Vertically Scrolling UIImage programmatically

Working on a small side project, I wanted to display images in my view controller view at full device width in a vertical scrolling view. Sounds simple right? The good news is that it is. While you may want to use UITableView for more control, using UIStackView is a simpler way to get up and running fast.

For my sample code, I opted to do it programmatically as it’s easier to copy & paste code than explain what constraints to add in Xcode. Also note that the code presented here is a proof of concept, quick and dirty example (not intended for production).

The steps are easy to understand:

  1. Add a scroll view to your view
            self.scrollView = UIScrollView()
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(scrollView)
    
            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
            scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
            scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
            scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
  2. Add a stack view to your scroll view
            self.stackView = UIStackView()
            stackView.translatesAutoresizingMaskIntoConstraints = false
            stackView.axis = .vertical
            stackView.spacing = 23.0
            scrollView.addSubview(stackView)
    
            scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[stackView]|", options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: ["stackView": stackView]))
            scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[stackView]|", options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: ["stackView": stackView]))
  3. Add images to your stack view
    stackView.addArrangedSubview(image(filename: "photo1"))

For the full code, read the ViewController on GitHub

Hope this helps you if you’re trying to throw together a quick prototype of vertically scrolling images in iOs.

LA Boba Shops

There is endless boba in Los Angeles. I currently live in Ktown where every block seems to have a boba shop, a patbingsu shop, or both.

It’s hard to rank boba joints, because the drink customization (sugar level) and drinks on the same menu vary so much. There could be a big difference between the house specialty (let’s say rose milk tea) and the random drink (almond milk tea).

I value the quality of the ingredients (made in house with real things instead of powder), the freshness of the pearls (boba), and the flavor profile (not mind-numbingly sweet). I’ve tried many dozens of boba joints in LA, and I usually order large, 50% sugar, and less ice.

Below are places that have consistently good drinks with a sample recommended order. Not every order is your standard PMT (pearl milk tea).

Good

  • Gong Cha
    • QQ Passion Fruit Green Tea (comes with pearls & coconut jelly)
      (fruity & refreshing)
  • Sharetea
    • Taro Fresh Milk Tea with Pearls
      (real taro bits is a plus)
  • Tan-Cha
    • High Mountain Green Tea with Cheese Foam
      (as a cheese foam drink, it is heavier than a PMT)
  • Ten Ren’s Tea Time
    • Honey Milk Tea with Pearls
      (their teas are underrated)
  • Twinkle Brown Sugar (Ozero)
    • Brown Sugar Grass Jelly
      (drinks like a meal)

Decent

  • 7 Leaves Cafe
    • Sea Cream Jasmine Tea with Honey Boba
      (crema top layer)
  • 85C Bakery
    • Sea Salt Mountain Green Tea
      (has a good foam/crema top layer. their boba is bad)
  • Kung Fu Tea
    • Jelly Wow
      (not a traditional PMT, more of a meal)
  • TPumps
    • Mango Passion Peach with Boba
      (tea is very “drinkable”, not the best, but it goes down well. boba is not fresh)
  • Wushiland Boba
    • Jasmine Green Milk Tea with Pearls
      (try 1/2 regular & 1/2 small pearls)

While I don’t inherently favor chains, I’ve found that big chains from Asia are more reliable and consistent with the boba freshness. Gong Cha 9 out of 10 times will have fresh boba, whereas your average LA boba shop will probably not have fresh boba.