top of page
  • Writer's pictureDon Peter

Whats new in store for developers with Swift 6.


New in Swift 6

Swift 6 introduces new and creative functionalities aimed at improving your coding experience and enabling you to develop more sturdy and effective applications.


Exploring the key features of Swift 6, from advancements in concurrency to fine-tuning functions, this blog post uncovers the top 4 highlights. Discover how these enhancements can enhance your development process and open up new opportunities for your projects.


1. Swift Concurrency Isolation

Swift Concurrency is designed to ensure data safety by implementing a system that isolates code execution with actors. Actors in Swift are a concurrency feature introduced in Swift 5.5. They are designed to protect their state from data races and ensure that only one piece of code can access an actor's data at a time. By confining code execution within these isolated units, Swift Concurrency minimizes the risk of conflicts arising from simultaneous access to shared data. In order to send data between these units, developers has to use Sendable types. You can read in detail about sendable types here https://developer.apple.com/documentation/swift/sendable


However, while this mechanism enhances data safety, it also introduces certain constraints on programming practices. Specifically, some commonly used patterns involve non-Sendable data, like classes or mutable structs, which refers to data that is not inherently safe to share across different contexts. This is because using non-Sendable types concurrently can lead to data races and compiler warns developers against it.


This limitation can impact how developers write their programs, as they must carefully consider the implications of sharing non-Sendable data within the context of Swift Concurrency.



// Not Sendable
class Client {
  init(name: String, initialBalance: Double) { ... }
}

actor ClientStore {
  var clients: [Client] = []

  static let shared = ClientStore()

  func addClient(_ c: Client) {
    clients.append(c)
  }
}

func openNewAccount(name: String, initialBalance: Double) async {
  let client = Client(name: name, initialBalance: initialBalance)
  await ClientStore.shared.addClient(client) // Error! 'Client' is non-`Sendable`!
}

1.1 Introducing Isolation Regions

Swift 6 introduces a new feature known as isolation regions, which revolutionizes the way the compiler comprehends data usage and ensures security during the transmission of non-Sendable values across isolation boundaries like actors. Isolation regions essentially equip the compiler with the ability to analyze how data is utilized, thereby enabling it to ascertain whether two data entities have the potential to influence each other and cause data race situations.


There is nothing specific for the developer to do for this capability to be activated, except upgrading to Swift 6.


2. Count and Filter

Swift now includes a nifty feature called count(where:). This method lets you efficiently count elements in a collection that meet a specific condition. It combines the functionality of filter() (which creates a new array with matching elements) and count() (which calculates the number of elements) into a single step.


let testScores = [70, 85, 90, 68, 95]
let passingCount = testScores.count(where: { $0 >= 85 })

print("Number of tests with scores 85 or higher:", passingCount)

This not only saves you from creating unnecessary temporary arrays, but also provides a cleaner and more readable way to achieve this common task.


The beauty of count(where:) is that it's not limited to just arrays. It works with any collection type that conforms to the Sequence protocol, including sets and dictionaries. This gives you a powerful and versatile tool for working with various data structures in Swift.


3. Error Handling with Typed Throws

Swift introduces a much-awaited feature: "typed throws." This eliminates a common frustration with error handling - the need for a general catch clause even when you've caught all specific errors.



enum RegistrationError: Error {
    case notAlphaNumbericChars
}

  • Specificity: You can now declare precisely what types of errors a function can throw using throws(OneSpecificErrorType). This signals that only that specific error type can be thrown by the function.

  • Cleaner Code: Since Swift knows the exact error type, you can write more concise code. For example, if your function throws only RegistrationError, you can write throw .notAlphaNumbericChars instead of a generic error message.


do {
    register()
} catch RegistrationError.notAlphaNumbericChars {
    print("Please make sure password filed contains alpha numberic Characters")
}

  • Automatic Type Inference: In a do block that throws only one type of error, the error value in a general catch block automatically becomes the specific error type instead of a generic Error.

  • Improved Safety: Swift throws a compile-time error if you attempt to throw an error not listed in the throws clause.

  • Expressive Rethrows: You can write rethrows more clearly in many cases. For example, throws(any Error) is equivalent to just throws, and throws(Never) signifies a non-throwing function.


4. Internal Imports within Modules

Imagine a large e-commerce application with a modular architecture:

  • Core Functionality: This core module handles essential functionalities like product management, shopping cart handling, and user authentication.

  • Payment Processing: This separate module deals with secure payment processing and integrates with various payment gateways.

  • Analytics & Logging: This module is responsible for tracking user interactions, logging events, and potentially utilizing third-party analytics services.


4.1 Challenge: Dependency Management

The core application depends on both Payment Processing and Analytics & Logging modules. However, ideally, the core functionality shouldn't expose these internal dependencies to other parts of the codebase.



internal import <ModuleName>

4.2 Access Control Modifiers to the Rescue

Swift 6.0's access control modifiers on import statements come in handy here:

  1. Private Imports: The core module can privately import the Payment Processing and Analytics & Logging modules. This ensures that these dependencies are not accidentally exposed or used outside the core module.

  2. Encapsulation and Security: By keeping payment processing and analytics private, the core module promotes better encapsulation and potentially strengthens security by limiting access to sensitive functionalities.



These are the top 4 new features in Swift 6.0, in my opinion.


Happy Coding and Bug Fixing.




Blog for Mobile App Developers, Testers and App Owners

 

This blog is from Finotes Team. Finotes is a lightweight mobile APM and bug detection tool for iOS and Android apps.

In this blog we talk about iOS and Android app development technologies, languages and frameworks like Java, Kotlin, Swift, Objective-C, Dart and Flutter that are used to build mobile apps. Read articles from Finotes team about good programming and software engineering practices, testing and QA practices, performance issues and bugs, concepts and techniques. 

Monitor & Improve Performance of your Mobile App

 

Detect memory leaks, abnormal memory usages, crashes, API / Network call issues, frame rate issues, ANR, App Hangs, Exceptions and Errors, and much more.

Explore Finotes

bottom of page