Chris Downie - Big Nerd Ranch Tue, 19 Oct 2021 17:47:12 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 Building Quality iOS Apps, Quickly https://bignerdranch.com/blog/building-quality-ios-apps-quickly/ Tue, 07 Jan 2020 14:19:11 +0000 https://nerdranchighq.wpengine.com/?p=4049 At Big Nerd Ranch, we take pride in building quality apps for our clients. Unfortunately, quality isn't the only concern when building an app for your business. Often, it's also important to get these apps to the App Store as quickly as possible.

The post Building Quality iOS Apps, Quickly appeared first on Big Nerd Ranch.

]]>
At Big Nerd Ranch, we take pride in building quality apps for our clients. But quality isn’t the only concern when building an app for your business. Often, it’s also important to get these apps in the App Store as quickly as possible. So how do we uphold our ideals for quality while still delivering our apps on time and on budget?

Fortunately, it’s not impossible. Here are three best practices that we use (and recommend others use, too!) to deliver iOS, iPadOS, tvOS, and macOS apps to market.

Unit Testing

There’s just no way around it – the only way to know that an app does what it’s supposed to do is to test it. However, having a large group of manual QA testers can be a costly approach to ensuring quality. A more cost-effective way to engineer a quality app for an Apple platform is to write the code that tests the app itself.

But not all apps are equally testable. In order for a test to have the maximum impact on app quality and speed of delivery, apps need to be built from the ground up with testability in mind. When building an app to be testable, we recommend that apps:

  • Are built modularly, with single-responsibility components that can keep unit tests focused
  • Use dependency injection to unit test each component in isolation
  • Have unit tests written as features are built, so new functionality is proven to work before a user even sees it

This unit testing discipline not only improves the overall quality of the app, but it helps in the speed of delivery. A well executed test plan means less time spent investigating bugs and more time spent building features.

Logging

Nevertheless, bugs still happen. A good unit testing discipline only prevents defects you can anticipate. How can you minimize engineering time spent investigating user-reported bugs so they can spend more time building features?

Our recommended approach to solve this problem is a thorough logging discipline. We recommend that all apps use CocoaLumberjack to:

  • Log any user interaction
  • Log any significant errors or unusual state
  • Share the logs directly from device with a UIActivityViewController

This can substantially reduce the time it takes to find and fix an issue. Rather than asking a user to self-report everything they did to end up in a weird state, they can just send an email to the developers with a log that looks like this:

[Authentication] User cdownie@bignerdranch.com logged in.
[Settings] Settings icon tapped.
[Settings] Edit Address tapped.
[Settings] Save Address tapped.
[Settings] Error: Updating the user address failed with error: { status: 403, error: "Zip code did not match provided city & state" }

 

Continuous Integration

While these (and other) code quality tasks are important, they can also quickly become a project maintenance burden. If you’re manually running unit tests, ensuring code consistency with a linter, or submitting periodic builds to TestFlight, that’s time that could otherwise be spent building features and delivering value to your users. Additionally, these manual chores are all too easy to accidentally skip when pressed for time.

So, automate it! The fastest chore is the one you don’t have to do. We recommend configuring a continuous integration server like CircleCI to run these tasks for you. Specifically, we recommend:

  • Running code-quality tasks on both master and feature branches
  • Parallelizing long-running tasks to improve the speed of the continuous integration system
  • Generating a new, versioned build of your app for every commit to master
  • Uploading these new builds to TestFlight automatically with fastlane

That last point is particularly important. With frequently updated builds sent out regularly to early beta testers, you can get early feedback on your app’s progress. Crucially, this can tell you what features to focus further development on. All without impacting the engineering team’s speed of delivery.

Deliver Quality, Quickly

With these techniques in hand, your engineering team should now be able to:

  • Deliver high-quality features with unit tests
  • Debug issues quickly with concise user-generated logs
  • Iterate quickly on early user feedback with continuous integration

Best of all, you can do all of this while keeping the engineering team focused on delivering new features.

If this all seems overwhelming, not to worry. At Big Nerd Ranch, we have decades of experience applying these best practices and more to build apps quickly, confidently, and with quality. We would be more than happy to make your idea for an iOS, iPadOS, tvOS, or macOS app a reality. Feel free to schedule a call with us today.

The post Building Quality iOS Apps, Quickly appeared first on Big Nerd Ranch.

]]>
Detecting carAudio https://bignerdranch.com/blog/detecting-caraudio/ Thu, 24 Oct 2019 15:52:30 +0000 https://nerdranchighq.wpengine.com/?p=3901 How can you detect when the user connects their phone to their car’s stereo? This simple question that came up during a feature brainstorm session proved to have a surprisingly complicated answer. Let’s dive in.

The post Detecting carAudio appeared first on Big Nerd Ranch.

]]>
How can you detect when the user connects their phone to their car’s stereo? This simple question that came up during a feature brainstorm session proved to have a surprisingly complicated answer. Let’s dive in.

Background on AVAudioSession

Audio on iOS is mostly handled by the OS itself. You communicate your intent to play audio by telling an instance of AVAudioSession (usually its singleton sharedInstance()).

Most important for this discussion, are the available audio routes on the shared AVAudioSession instance. Each audio route is either an input that’s receiving audio (like the phone’s microphone) or an output where we’re sending audio (like the phone’s speaker or a bluetooth headset). We can access the shared AVAudioSession’s current route, and inspect all of its outputs:

let audioSession = AVAudioSession.sharedInstance()
audioSession.currentRoute.outputs.forEach { output in
    print(output.portName)
}

Each output is of type AVAudioSessionPortDescription. Conveniently, in addition to each port having a name, it also has a type that’s one of these AVAudioSession.Port values. Among them is a convenient value called carAudio.

So! This should be easy! Monitor for changes to the ports in the shared audio session, and when we see one of type .carAudio, then we’re connected to a car!

Not So Fast

Turns out, there are a lot of ways to connect your iPhone to your car’s stereo:

  • A lightning-to-USB cable directly to the stereo system
  • The lightning-to-aux adapter
  • Direct bluetooth connection to the car
  • Bluetooth connection to an after-market stereo adapter
  • Bluetooth connection to a CarPlay-enabled car

Do these all report as .carAudio? Can we distinguish connecting to a car via bluetooth from connecting to AirPods? Can we distinguish between a lighting connection to EarPods and a lightning connection to a car?

To answer these questions, we built a little test app and passed it around the office. The app is pretty simple:

  1. Listen for any changes to the audio route by registering for AVAudioSession.routeChangeNotifications
  2. When a change occurs, record the reason for the change
  3. After each change, look at all the route’s output port descriptions, and record their name & type.

You can experiment with the app yourself by downloading it here.

The Results

Here’s a quick table of our results, showing the type of connection, if it’s actually a connection to a car, and the port’s portType value:

Connection Car? Port Type
After-market bluetooth-to-aux device Yes .bluetoothA2DP
Bose Bluetooth headphones No .bluetoothA2DP
AirPods No .bluetoothA2DP
Direct connection to car’s bluetooth Yes .bluetoothA2DP
Lightning-to-headphone adapter + aux Yes .headphones
Lightning EarPods No .headphones
iPhone to Car’s USB port Yes .usbAudio
Screen mirror to Apple TV No .airPlay
Bluetooth to a CarPlay-enabled car Yes .carAudio

We finally saw a .carAudio value, but only when directly connected to a CarPlay-enabled car. Even cars with native bluetooth support reported the connection as .bluetoothA2DP — just like any other bluetooth speaker.

However, these bluetooth connections do provide useful data. Each .bluetoothA2DP connection also provides an identifiable name and a unique ID. Rather than automatically connect to all cars with bluetooth support, we discovered it would be possible for the user to identify a specific bluetooth device (such as their car) they’re already connected to and the app would know whenever the user connects to that device again. That will have to do for now.

The post Detecting carAudio appeared first on Big Nerd Ranch.

]]>
Automating TestFlight Builds with CircleCI – Part 2 https://bignerdranch.com/blog/automating-testflight-builds-with-circleci-part-2/ https://bignerdranch.com/blog/automating-testflight-builds-with-circleci-part-2/#respond Tue, 30 Jul 2019 17:47:02 +0000 https://nerdranchighq.wpengine.com/?p=3776 Automate your build and deploy process with fastlane and CircleCI! We'll build on our fastlane commands from Part 1 and show how to configure CircleCI to invoke them automatically.

The post Automating TestFlight Builds with CircleCI – Part 2 appeared first on Big Nerd Ranch.

]]>
In Part 1, we set up two Fastlane commands:

  1. bump to increment the build number and
  2. submit_to_testflight to upload the build to our TestFlight group

Let’s configure CircleCI to run these commands for us when new features are delivered to our master branch.

Initial CircleCI Setup

Let’s tell Circle CI that we want it to run some projects for us. Click on CircleCI’s Add Projects tab. Find your repository in the list and click Set Up Project. Follow the initial setup steps on that page and then click Start Building.

Bump the build number

In config.yaml, add a new job to your job list:

  bump-build:
    macos:
      xcode: "10.2.0"
    environment:
      # Silences warning from Fastlane
      - LC_ALL: "en_US.UTF-8"
      - LANG: "en_US.UTF-8"
    steps:
      - checkout
      # Install fastlane and its dependencies
      - run:
          name: install Brewfile
          command: brew bundle
      - run:
          name: Installing gem dependencies
          command: bundle install
      # Securely connect to GitHub
      - add_ssh_keys:
          fingerprints:
            - "SO:ME:FI:NG:ER:PR:IN:T"
      # Call the bump lane
      - run:
          name: Bump the build number and commit
          command: bundle exec fastlane bump

The interesting part is add_ssh_keys. Deployment keys let CircleCI access your code. However, while you can set a service deployment key in CircleCI, it only gives read access. The fastlane bump command needs write access to push the version bump commit to master. Therefore, we need to generate and register a user-deploy key with write access by following these instructions. Paste the key’s fingerprint here.

Notably:

  • That key should be added to the project repository’s settings in GitHub
  • The fingerprint in this step should match.

Submit to TestFlight

Let’s add the job for submitting to TestFlight:

submit_to_testflight:
    macos:
      xcode: "10.2.0"
    environment:
      # Silences warning from Fastlane
      - LC_ALL: "en_US.UTF-8"
      - LANG: "en_US.UTF-8"
    steps:
      - checkout
      # Install fastlane and its dependencies
      - run:
          name: install Brewfile
          command: brew bundle
      - run:
          name: Installing gem dependencies
          command: bundle install
      # Securely connect to GitHub
      - add_ssh_keys:
          fingerprints:
            - "SO:ME:FI:NG:ER:PR:IN:T"
      # Call the submit lane
      - run:
          name: Deploy new build to TestFlight
          command: bundle exec fastlane submit_to_testflight

This looks very similar to the step for making the build. In fact, the only differences are:

  1. We install a different SSH key
  2. Our final run command is now fastlane submit_to_testflight

This SSH key is the one Circle CI will use to download your credentials from the repo that fastlane match uses to store them. If you attempt to reuse your key from earlier, GitHub will reject it. Instead, you’ll need to do the same key generation process again, and add the fingerprint for the SSH key associated with the credentials repo here.

Build the workflow

Now that we’ve got two jobs, let’s put them together into a workflow: 

#Defines work-flows for the jobs specified above
workflows:
  version: 2
  build-test-lint:
    jobs:
      - build-and-test:
          filters:
            tags:
              only: /.*/
      - bump-build:
          requires:
            - build-and-test
          filters:
            branches:
              only: master
            tags:
              only: /.*/
      - deploy-beta:
          requires:
            - build-and-test
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /^builds.*/

That’s a lot. Let’s look at each job in that workflow individually.

- build-and-test:
    filters:
      tags:
        only: /.*/

This builds and tests any commit to any branch. See CircleCI’s excellent guide on how to configure automated tests.

The filter here is odd. Why would we filter to a regex that matches everything? This is how CircleCI knows it should trigger this workflow for either a tag match or a branch match. It looks superfluous right now, but adding the “only run it for every tag” filter means we can specify “only run it for specific tags” in later, dependent jobs.

- bump-build:
    requires:
      - build-and-test
    filters:
      branches:
        only: master
      tags:
        only: /.*/

This runs our fastlane bump job. This will only run on the master branch, and will run with any specified tag. And, it’ll only run after build-and-test successfully completes.

Just like before, the “filter to only all of the tags” looks superfluous, but it’s not. Now that our parent task has started filtering for tags, if any job doesn’t specify a tag filter, then all tag filters will be ignored.

And now, the grand finale of CI config:

- deploy-to-testflight:
    requires:
      - build-and-test
    filters:
      branches:
        ignore: /.*/
      tags:
        only: /^builds.*/

Finally, our deploy task ignores branches and only triggers if it sees a tag that starts with builds. You can probably make the tag regex more specific, but this is good enough for me.

Both of these filters values are OR’d together. If we specified branches: only: master with this filter tag, then it would run for every commit on master and also any commits that start with builds. Ignoring the branch entirely and having builds tags only added to master is the only way to achieve the desired effect.

Your automated process should now look like this:

Configure the CircleCI Environment

You’re still not done! There’s some state on your local machine that you need to go into CircleCI and add as environment variables. Specifically:

  • MATCH_PASSWORD – This is the password you use to decrypt your fastlane credentials.
  • FASTLANE_PASSWORD – This is the Apple ID password of the account you use to submit builds to Apple.

If the shared build account follows fastlane’s recommendation and doesn’t have two-factor authentication enabled, then you’re done. Otherwise, you’ll need these additional environment variables:

  • FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD – This can be generated in Apple ID Settings, underneath Security > Generate Password.
  • FASTLANE_SESSION – A session token that’s sufficent for two-factor authentication. To generate, type the following command in the terminal, using the build account’s email address: fastlane spaceauth -u user@email.com

The FASTLANE_SESSION expires after a month. You will need to update this environment variable monthly in order to keep the build process automatic. Unfortunately, that’s the best fastlane can do.

Hope for the best

That’s it! Make your commits, get them reviewed and merged to master, and about 20-30 minutes later you should get a notification that you’ve got a new build to download from TestFlight.

If you’re anxiously watching the workflow process as this goes on, you should see each of the five jobs:

  1. Test your commit with build-and-test.
  2. Increment the build number with bump-build and tag the commit.
  3. Test the build tag commit with build-and-test
  4. Re-run bump-build with no effect on the tag commit.
  5. Deploy with deploy-to-testflight.

The post Automating TestFlight Builds with CircleCI – Part 2 appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/automating-testflight-builds-with-circleci-part-2/feed/ 0
Automating TestFlight Builds with CircleCI – Part 1 https://bignerdranch.com/blog/automating-testflight-builds-with-circleci-part-1/ https://bignerdranch.com/blog/automating-testflight-builds-with-circleci-part-1/#respond Wed, 24 Jul 2019 17:05:13 +0000 https://nerdranchighq.wpengine.com/?p=3767 Automate your build and deploy process with fastlane and CircleCI! In this first part, we'll describe our current process and illustrate how we can reduce it down to a series of fastlane commands.

The post Automating TestFlight Builds with CircleCI – Part 1 appeared first on Big Nerd Ranch.

]]>
Keeping the entire team on the same build of your in-progress app is a pain. There are a handful of automated steps, and long gaps of time while you wait for Apple servers to propagate your data. Let’s automate this process so you can set it once and forget about it.

The Goal

Our goal is to take our existing process and automate it with CircleCI. For this example, our current process is:

  • Run agvtool bump -all to update the build number. What’s agvtool?
  • Commit and push that version bump
  • In Xcode, archive the project and submit to TestFlight
  • Wait for the build to upload and process
  • In App Store Connect, distribute the build to our test team.

The Plan

How does this translate to an automated system? We’ve got some kinks to work out.

Adding commits triggers a build loop

We want this build to run on every commit to master. Part of our process is to add a git commit to master (the commit that increases the build number by one). This is a recipe for infinitely increasing your commit count. #protip

We’ll plan on checking the latest commit to make sure it’s not a build commit before adding a new one. We’ll also add a tag to this commit, which will be useful later.

We can’t submit a given build number more than once.

Our CI process will be invoked twice — once for the change to master, and once for the build bump commit. If we submit to TestFlight on both of those builds, the second one will always fail. That’s bad. The last thing we want to do is make the team comfortable with CI task failures.

We can use some of the job filtering that CircleCI provides us to make sure we only try to submit a build once, after we’ve committed our build bump.

We need Apple signing credentials to submit to TestFlight

While fastlane handles a lot of this work for us, it means the CI system needs access to two repositories — one with the code and one with our fastlane– managed signing credentials. Since GitHub prevents you from using a single deploy key more than once, this isn’t as easy as it sounds.

We’ll plan on making two deployment keys, one for each repo, and configuring the CI system to use the right one at the right time.

Distributing a build requires build notes

Obviously, you could just hardcode “bug fixes and improvements,” but we can do better. So we will! Let’s aggregate the commit messages since our last build into a short list as the notes to submit to TestFlight.

We can re-use the build tags we need above in order to make sure we get an accurate description of what’s changed since the last build we sent out.

First Step: Perform Major Actions with Fastlane

Let’s pause our CI ambitions for a moment and focus on reducing this process with multiple applications and websites into a sequence of Terminal commands. Fastlane can handle most of the heavy lifting here.

Configuration in the Fastfile

Bump the build number

Let’s look at how we do build bumps first. In our Fastfile, we added a new lane named bump:

desc "Bump and tag version"
lane :bump do
  ensure_git_status_clean
  bump_message = "Bump build number."

  # If our latest commit isn't a build bump, then bump the build.
  build_is_already_bumped = last_git_commit[:message].include? bump_message
  next if build_is_already_bumped

  increment_build_number
  commit_version_bump(
    message: bump_message,
    xcodeproj: "Project.xcodeproj"
  )
  add_git_tag
  push_to_git_remote
end

The tricky thing here is determining if the latest commit was a build bump. We had to do include? rather than a straight equality check, since the last_message value includes a newline at the end of it for some reason. Then we tag the commit with the build number and push to remote.

Submit to TestFlight

Now let’s see how we got the thing to submit to TestFlight.

desc "Submit latest versioned build to testflight"
lane :submit_to_testflight do |options|
  # 1. Do some math to get build tags
  build_number = get_build_number(xcodeproj: PROJECT_PATH)
  last_build_number = build_number.to_i - 1
  build_tag = "builds/iosbump/" + build_number
  last_build_tag = "builds/iosbump/" + last_build_number.to_s

  # 2. Generate a change log
  comments = changelog_from_git_commits(
      between: [last_build_tag, build_tag],
      pretty: "- %s",
      date_format: "short",
      match_lightweight_tag: false,
      merge_commit_filtering: "exclude_merges"
  )

  # 3. Build the app
  match(type: "appstore", readonly: true, skip_docs: true)
  target_scheme = options[:scheme] || "MyApp-Debug-Development"
  build_app(scheme: target_scheme)

  # 4. Upload it to testflight
  groups = options[:groups] || "All Builds"
  upload_to_testflight(
    changelog: comments,
    distribute_external: true,
    groups: groups
  )
end

Let’s look at each of these four sections more closely:

  1. Here, we create last_build_tag and build_tag based on the tags that we generated in the above lane. Note that this is the default output of add_git_tag from that script. Most notably, while everything else can be configured, the lane part of the tag cannot. So if you named the above lane bump like we did, then the tag will have iosbump in the middle.
  2. This compiles the commits between those two tags into a nicely formatted list. For example:
    - Bump build number.
    - Fixes errors and warnings caused by pod update.
    - Updates MyPodDependency pod from 0.4.1 to 3.0.0.
    
  3. Here we get the credentials, make the build. Note that our scheme has to match the profile type configured in our .xcodeproj file.
  4. Finally, upload the build to TestFlight. The groups value matches a previously-added group in App Store Connect.

One more thing

This won’t have any effect yet, but when CircleCI does run these commands later, it’ll complain. Even though it can download the credentials, it has nowhere to store them. You need to add a line that should run before every lane:

```ruby
before all do |lane|
  setup_circle_ci
end
```

“But wait,” you ask, “can’t I just do that at the top of our submit_to_testflight lane, since that’s the only place we need it?” Maybe. But you might write other lanes and forget this step later. The docs say to do it before every lane. I’d do what they say.

Good to go

At this point, you can distribute builds from the terminal with two commands:

  1. fastlane bump
  2. fastlane submit_to_testflight

Hooray! That’s way better!

However, our goal is to avoid even having to type these two commands. To accomplish that, we’ll have to configure CircleCI to run these commands in Part 2.

The post Automating TestFlight Builds with CircleCI – Part 1 appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/automating-testflight-builds-with-circleci-part-1/feed/ 0
Xcode: All the Way to 11 https://bignerdranch.com/blog/xcode-all-the-way-to-11/ https://bignerdranch.com/blog/xcode-all-the-way-to-11/#respond Mon, 24 Jun 2019 09:00:00 +0000 https://nerdranchighq.wpengine.com/blog/xcode-all-the-way-to-11/ At WWDC, Apple debuted Xcode 11 with a diverse array of interface refinements, tool improvements, and major new features. Let's take a look at some of the key changes that should greatly improve your day-to-day coding experience.

The post Xcode: All the Way to 11 appeared first on Big Nerd Ranch.

]]>

At WWDC, Apple debuted Xcode 11 with a diverse array of interface refinements, tool improvements, and major new features. Let’s take a look at some of the key changes that should greatly improve your day-to-day coding experience.

Editor Changes

The most noticeable feature in Xcode 11 is the editor. Gone is the pillbox/drop down button for switching states between editor view, assistant view, and author view. In their place is a single Code Review button.

Toolbar buttons for Xcode 10.2 side-by-side with the one button in Xcode 11.

However, all is not lost. The Author view and the Assistant view have moved into a toggle on the editor itself. The Log view has moved into an Inspectors tab and has been renamed History.

The new History inspector, showing 2 commits.

In fact, the Editor Options button now gives you a context-sensitive editor. You can choose between Editor Only, Editor & Canvas (for Swift UI), and Editor & Assistant, which mimics the old behavior of Assistant view.

Editor Options button clicked, showing "Editor Only", "Editor and Canvas", and "Editor and Assistant" options in the dropdown

Moving this option into the editor is especially powerful considering…

Multiple Editors

You can now customize your workspace by opening any number of editors in any mishmash of horizontal & vertical configurations.

Five columns of editor windows are shown with anywhere from one to five editors in each column.

Each of these editors provide the same options in the Editor Options dropdown, letting you fully customize the exact views into your project that you want to see at one time. By default, you can add another column to the right by clicking the Add Editor button, and add a row below by option-clicking that button instead. This button is context-sensitive, so whether a row or a column gets added depends on which kind you added previously. However, holding option always changes the icon and lets you add an editor in the opposite dimension.

A comparison between the Add Editor Below and the Add Editor to the Right buttons

While you can slice-and-dice your screen to your heart’s content, eventually you’ll want to focus on one implementation. When that moment comes, you can dedicate all your on-screen real estate to the problem at hand by clicking the Focus button (or key command ⌃⇧⌘↩︎).

Clicking on the expand button causes the editor to take up the full window.

Once you’ve got your grid of editors set up, you can also quickly cycle between them by using the ⌘` key command.

Don’t forget about the mini-map

Each editor also gets its own mini-map, a stylized overview of the shape of your code, in the top right corner. This has been present in other IDEs for some time and is a welcome addition to Xcode.

An Editor view showing the new mini map

Xcode’s mini-map works especially well with MARK comments. If you’ve made it a regular habit of grouping sections of your code with a // MARK: - Title, then those titles show up legibly in the mini-map.

Unlike other editors, the mini-map is interactive. You can click on those section headers, or on functions in your code to jump around in your editor view

Clicking on a method causes Xcode to scroll the editor to that method.

However, if you’re not a fan of the thousand-foot view of your code, you can always disable the mini map by selecting the Hide Mini Map option from the Editor Options dropdown.

Swift Package Manager

While CocoaPods and Carthage will still remain relevant dependency managers for the foreseeable future, Xcode 11’s deep integration with the Swift Package Manager makes it the de facto way to manage Swift dependencies going forward. Adding a Swift Package to your existing project is as easy as entering the repository URL into a prompt.

“Add Package Dependency” screen, filled with GitHub repos

This works for private Swift packages as well. If you have a package you want to share internally, just make sure to add the GitHub, GitLab, or Bitbucket account to Xcode, and the repository prompt will be pre-populated with private Swift packages you can access.

Xcode can also resolve Swift Package Manager dependencies against local code. If you’re developing your own package, or hacking someone else’s for fun and profit, you can add the package folder directly to your project. Xcode is smart enough to realize it’s the same as the one specified in your dependencies, and will resolve to your local copy instead of the one specified in your dependency file.

SwiftUI

This wouldn’t be a complete WWDC 2019 blog post without mentioning SwiftUI. While an upcoming blog post will talk about SwiftUI as a framework, for now let’s just discuss what it feels like to edit Swift UI.

It’s fast. With the Editor & Canvas editor style selected, you get an Assistant-like view of your code & its display all at once. After an initial build, changes made to the code are quickly reflected in the Canvas. Similarly, the canvas provides an Interface Builder-style visual means to change your layout that instantly adjusts the underlying code to match your changes.

Changing a Text node in the editor shows the changes immediately in the Canvas view.

However, the Canvas view is much more powerful than a simple Storyboard. You can configure the Canvas to show what your view looks like under a variety of conditions: different dimensions, text sizes, and yes, even the much-touted Dark Mode new to iOS 13.

The same view, shown with different color variations

Finally, the Canvas can be used to actually test the interaction of your app. While looking at an iPhone-shaped preview of your app, just click the Live Preview button. Don’t blink! I’ve had this switch from preview to running app so quickly I missed it.

Pressing the play icon in the Canvas lets you run the app

A small caveat: All the nimble new features of the Canvas screen only work well on macOS Catalina, at least as of Xcode 11 beta 2. Hopefully we’ll see this improve as the betas progress.

Eleven is one better

All these features show Apple’s vision: the experience of writing apps for their ecosystem should be fast, configurable, and fun. Xcode 11 makes a considerable step forward to make this vision a reality, and I can’t wait to make it part of my daily toolchain.

The post Xcode: All the Way to 11 appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/xcode-all-the-way-to-11/feed/ 0