Skip to main content

7 posts tagged with "watchOS"

View All Tags

WHATS NEW IN STORE FOR DEVELOPERS WITH SWIFT 6.

Published: · Last updated: · 6 min read
Don Peter
Cofounder and CTO, Appxiom

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:

  • 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.

  • 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.

UPDATES FOR IOS DEVELOPERS IN THE EU: INTRODUCING WEB DISTRIBUTION

Published: · Last updated: · 4 min read
Don Peter
Cofounder and CTO, Appxiom

Apple is bringing more options for distributing your apps in the EU due to Digital Markets Act (DMA). Whether you’re a seasoned developer or just starting out, these changes are positioned as a way to reach more users and enhance your app distribution strategies.

Developers have the option to stick with the existing App Store business terms or opt for the new terms tailored for iOS apps in the EU. Under the new EU business terms, developers can decide to distribute iOS apps within the EU through the App Store, other alternative app marketplaces or through own hosting.

Alternative distribution channels

Following are the two additional methods for developers to distribute iOS apps in EU along with App store distribution,

  • Third party App Marketplaces: Now, third party marketplaces have the option to offer a catalog of apps. This opens up new avenues for app discovery and distribution.

  • Linking out to Purchase: Developers can now choose how to design promotions, discounts, and other deals when directing users to complete a transaction for digital goods or services on an external webpage. The Apple-provided design templates are now optional, giving you more control over your promotional strategies.

Introducing Web Distribution for iOS

One of the most exciting updates is the introduction of Web Distribution, which allows authorized developers to distribute their iOS apps directly from their own website. Here’s what you need to know,

  • With Web Distribution, you can distribute your iOS apps to EU users directly from your website, giving you more control over the distribution process.

  • Apple will provide access to APIs that facilitate app distribution from the web, integrate with system functionality, back up and restore users’ apps.

  • Apps offered through Web Distribution must meet Notarization requirements just like in macOS apps to protect platform integrity, ensuring a secure experience for users. You can read more on notarization requirements here https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution

Eligibility and Requirements

To be eligible for Web Distribution, developers must meet specific criteria and commit to ongoing requirements to protect users. Here’s what you need to know,

  • Developers must be enrolled in the Apple Developer Program as an organization incorporated, domiciled, and/or registered in the EU.

  • Must be a member of Good Standing in the Apple Developer Program for Two Continuous Years or More,

This means that developers need to maintain their membership in the Apple Developer Program for at least two consecutive years without any significant issues or violations.

  • It ensures that developers have been actively engaged with the program and have adhered to its terms and conditions for a substantial period.

  • App with More Than One Million First Annual Installs on iOS in the EU in the Prior Calendar Year,

This refers to the number of initial installations (installs) of an app on iOS devices in the European Union during a single year. The app must have achieved more than one million first annual installs specifically within the EU region during the previous calendar year.

  • The requirement doesn't state that the app must consistently maintain one million installs each year to remain in the program.

  • Developers must agree to various terms, including offering apps only from their developer account, being responsive to communications from Apple, publishing transparent data collection policies, and following applicable laws.

Payments, Fees, and Taxes

We want to ensure that developers have clarity on payments, fees, and taxes associated with Web Distribution. Here’s what you need to know,

  • A Core Technology Fee (CTF) will be charged by apple.

What is the Core Technology Fee (CTF)?

It's a fee that developers pay to Apple.

  • It shows appreciation for the tools and support Apple offers to developers.

  • How is it calculated?

Developers pay €0.50 for first annual installs over one million in the past 12 months.

If a user has installed the app in multiple devices it will be treated as a single install only.

  • If your app has more than one million installs in a year, you pay this fee for each additional install beyond that.

  • Why does Apple charge this fee?

It helps Apple to cover the costs of maintaining and improving the tools and services that developers use.

  • It supports ongoing investments in technology to benefit developers and users alike.

  • Nonprofit organizations, accredited educational institutions, or government entities based in the EU that have been approved for a fee waiver are exempt from the Apple Developer Program annual membership fee and the Core Technology Fee.

  • Developers are responsible for collecting, reporting, and remitting any required tax to the appropriate tax authorities for transactions that take place using Web Distribution.

COMBINE: A DECLARATIVE API FOR ASYNCHRONOUS DATA PROCESSING IN SWIFT

Published: · Last updated: · 4 min read
Don Peter
Cofounder and CTO, Appxiom

Combine is a framework for Swift introduced by Apple in 2019 that provides a declarative API. This makes it ideal for working with asynchronous data, such as network requests and user input. Combine is also a powerful tool for building reactive user interfaces.

In this blog post, we will take a look at the basics of Combine, including publishers, subscribers, and operators. We will also see how Combine can be used to build asynchronous applications and reactive user interfaces.

What is Combine?

Combine is a reactive programming framework that provides a declarative API for processing values over time. This means that you can describe the desired behaviour of your code without having to worry about the details of how it will be implemented.

Combine is based on the following concepts:

  • Publishers: Publishers emit values over time. They can be anything from network requests to user input.

  • Subscribers: Subscribers receive values from publishers. They can do things like map values, filter values, and perform other operations.

  • Operators: Operators are functions that combine publishers and subscribers. They can be used to perform common tasks, such as combining multiple publishers, filtering values, and retrying failed requests.

Using Combine to Build Asynchronous Applications in Swift

Combine is ideal for building asynchronous applications. This is because it provides a way to handle asynchronous events in a declarative way. For example, you can use Combine to make a network request and then subscribe to the response. The subscriber can then handle the response, such as mapping it to a model or displaying it in a user interface.

Here is an example of how to use Combine to make a network request:

let publisher = URLSession.shared.dataTaskPublisher(for: URL(string: "https://api.myhost.com")!)

publisher.subscribe(on: RunLoop.main) { data, _, error in
if let data = data {
let json = try JSONDecoder().decode(MyJSONModel.self, from: data)
// Do something with the model
} else if let error = error {
// Handle the error
}
}

This code creates a publisher that emits the response data from the network request. The subscriber then handles the response data, either mapping it to a model or displaying it in a user interface.

Using Combine to Build Reactive User Interfaces

Combine can also be used to build reactive user interfaces. This is because it provides a way to update user interfaces in response to changes in data. For example, you can use Combine to subscribe to a publisher that emits the current user location. The subscriber can then update the user interface to display the user's location.

Here is an example of how to use Combine to update a user interface with the current user location:

let publisher = locationManager.publisher(for: .location)

publisher.subscribe(on: RunLoop.main) { location in
// Update the user interface with the new location
}

This code creates a publisher that emits the current user location. The subscriber then updates the user interface to display the user's location.

Using custom Combine implementation

Let us take a look at using PassthroughSubject to implement asynchronous declarative API.

A PassthroughSubject is a type of publisher in Combine that emits any value that is sent to it. It does not have an initial value or a buffer of the most recently-published element. This makes it ideal for use in situations where you need to react to changes in data as they happen.

import Combine

let subject = PassthroughSubject<String, Never>()

subject.sink { string in
print(string)
}

subject.send("Hello, world!")
subject.send("This is a second message")

Here, the first line imports the Combine framework. This is needed to use the PassthroughSubject and sink operators.

The second line creates a PassthroughSubject publisher. This publisher will emit any string that is sent to it.

The third line attaches a sink subscriber to the PassthroughSubject publisher. The sink subscriber will print each string that is emitted by the publisher to the console.

The fourth and fifth lines send two strings to the PassthroughSubject publisher. These strings will be printed to the console by the sink subscriber.

Conclusion

Combine is a framework that provides a declarative API for processing values over time. This makes it ideal for working with asynchronous data and building reactive user interfaces. If you are new to Combine, I encourage you to check out the official documentation and tutorials.

I hope this blog post has given you a basic understanding of Combine. If you have any questions, please feel free to leave a comment below.

EXPLORING XCODE 15 BETA 3: BOOSTING IOS DEVELOPMENT EFFICIENCY

Published: · Last updated: · 4 min read
Don Peter
Cofounder and CTO, Appxiom

Being an iOS developer, it's essential to keep up with the latest tools and features to boost productivity and build outstanding apps. The recent launch of Xcode 15 beta 3 by Apple introduces numerous exciting features and improvements.

In this blog post, we'll delve into some of the significant enhancements introduced in this version and how they can empower developers to streamline their workflows, enhance app performance, and simplify localization efforts.

Expanded OS Support

Xcode 15 beta 3 supports the latest beta versions like iOS 17 beta 3, iPadOS 17 beta 3, visionOS 1 beta, macOS 14 beta 3, tvOS 17 beta 3, and watchOS 10 beta 3.

With the arrival of Xcode 15 beta 3, developers can now enjoy on-device debugging support for iOS 12 and later, tvOS 12 and later, and watchOS 4 and later. To take advantage of these features, it is necessary to have a Mac running macOS Ventura 13.4 or a more recent version.

Profiling Enhancements with Instruments 15

Xcode 15 beta 3 introduces Instruments 15, which includes a new RealityKit Trace template. This template equips developers with powerful profiling instruments for apps and games on visionOS.

The RealityKit Frames instrument provides a visual representation of frame rendering stages, while RealityKit Metrics helps identify rendering bottlenecks. With CoreAnimation statistics, 3D rendering statistics, and more, developers can diagnose and eliminate performance issues to deliver fluid and immersive experiences.

Xcode Cloud Enhancements

Xcode Cloud, Apple's continuous integration and delivery service, receives notable updates in Xcode 15 beta 3.

Developers can now benefit from continuous integration, enabling automatic building and testing of apps as code changes are made. Additionally, continuous delivery capabilities enable seamless deployment of apps to App Store Connect or TestFlight right after successful build and testing. These features simplify the app development process, ensuring faster iteration and feedback cycles.

Performance and Development Workflow Improvements

Xcode 15 beta 3 brings performance enhancements to expedite app development.

Faster build times empower developers to iterate and test their code more rapidly. Improved memory usage ensures that Xcode operates smoothly even with memory-intensive projects, enabling developers to focus on writing high-quality code without unnecessary interruptions.

Swift-C++/Objective-C++ Interoperability

With Xcode 15 beta 3, Swift now supports bidirectional interoperability with C++ and Objective-C++. This means developers can utilize a subset of C++ APIs in Swift and Swift APIs from C++. Enabling C++ interoperability via build settings opens up new possibilities for integrating existing codebases and leveraging the strengths of both languages.

For more details on the topic, please refer https://swift.org/documentation/cxx-interop

Accessibility Audit Support

To enhance app accessibility, Xcode 15 beta 3 introduces Accessibility Audit support. This automated check helps identify various accessibility issues within your app's views. By utilizing XCUIApplication().performAccessibilityAudit(), developers can proactively address missing labels, text scaling with Dynamic Type, and low contrast, ensuring their apps are accessible to a wider audience.

Streamlined Localization with String Catalogs

Xcode 15 beta 3 introduces String Catalogs (.xcstrings) as a file type for managing app localization. Developers can easily extract localizable strings from their source code, keeping String Catalogs in sync.

The native editor allows for efficient previewing and management of localized strings, simplifying the localization process and ensuring a smooth experience for international users.

Build System Enhancements with Explicit Modules

Xcode 15 beta 3 brings improvements to the build system, including a new mode called explicit modules. This opt-in feature enhances build performance, reliability, and correctness.

Developers can enable explicit modules by setting _EXPERIMENTAL_CLANG_EXPLICIT_MODULES as a user-defined build setting in C and Objective-C projects, which significantly improves the overall development experience.

Conclusion

Xcode 15 beta 3 introduces several groundbreaking features and improvements designed to enhance the iOS development experience. From advanced profiling tools to accelerated build times and streamlined localization, developers have an arsenal of resources at their disposal. Embracing these enhancements will empower developers to create exceptional apps that leverage the latest platform capabilities. As Xcode continues to evolve, developers can look forward to increased productivity and a more streamlined development process.

Happy coding!

EXPLORING APPLE WWDC 2023: MAJOR FEATURE ANNOUNCEMENTS FOR IOS DEVELOPERS

Published: · Last updated: · 8 min read
Don Peter
Cofounder and CTO, Appxiom

Apple's Worldwide Developers Conference (WWDC) is an eagerly anticipated annual event where the company unveils its latest software updates and development tools. In 2023, WWDC introduced several exciting features for developers, aimed at enhancing the app development experience and expanding the reach of apps across various Apple devices.

Let's dive into the major feature releases for developers announced at Apple WWDC 2023.

Swift Macro

Version 5.9 introduced the concept of macros to Swift. Macros can be categorized into multiple smaller types.

  • ExpressionMacro to generate expression.

  • AccessorMacro to add getters and setters.

  • ConformanceMacro makes a type conform to a protocol.

Let's take a look at a basic macro to see how they function. Macros have the advantage of being executed during compile time.

Defining the AuthorMacro

One useful macro can be created to generate the file author name.

In MyMacrosPlugin.swift:

import Foundation
import SwiftSyntax
import SwiftSyntaxMacros

public struct AuthorMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
let argument = node.argumentList.first?.expression
let segments = argument.as(StringLiteralExprSyntax.self)?.segments

return "Autor: \(segments.first.content.text)"
}
}

This code defines a Swift macro named AuthorMacro that prints the author name from the string literal passed to it.

  • The AuthorMacro struct implements the ExpressionMacro protocol, allowing it to expand macros involving expressions.

  • The expansion function takes in a macro invocation and context and performs the following checks:

It ensures that the macro is invoked with a single argument that is a static string literal.

  • It appends the greeting message to the string.

The function returns an expression representing the constructed greeting message.

Declare Macro in Main Project

@freestanding(expression) 
public macro author(_ stringLiteral: String) -> String =
#externalMacro(module: "MyMacrosPlugin", type: "AuthorMacro")

Adding a string parameter and declaring the macro in our app target is a straightforward process. By incorporating the string parameter, we can enhance the macro's functionality and customize its behavior based on the specific needs of our application.

This flexibility allows us to pass dynamic string values to the macro, enabling more versatile and adaptable macro expansions.

Calling the Macro

print(#author("Mark")) //prints "Author: Mark"

In order to use this macro simply call #author and pass the String as parameter. The macro will print the Author name.

Macros can be a powerful tool for improving the readability, performance, and functionality of your Swift code. However, it is important to use them carefully, as they can also make your code more difficult to understand and maintain.

Here are some tips for using macros:

  • Keep your macros short and simple.

  • Use descriptive names for your macros.

  • Document your macros thoroughly.

  • Test your macros thoroughly.

  • Use macros sparingly.

By following these tips, you can use macros to write more concise, efficient, and powerful Swift code.

SwiftData

One of the highlights of Apple WWDC 2023 was the introduction of SwiftData. This new framework enables developers to seamlessly connect their data models to the user interface in SwiftUI.

Creating a Model

To enable saving instances of a model class using SwiftData, import the framework and annotate the class with the Model macro. This macro modifies the class to conform to the PersistentModel protocol, which SwiftData utilizes to analyze the class and generate an internal schema.

By default, SwiftData includes all noncomputed properties of a class, provided they use compatible types. The framework supports primitive types like Bool, Int, and String, as well as more complex value types such as structures, enumerations, and other types that conform to the Codable protocol.

import SwiftData

// Annotate with the @Model macro.
@Model
class Task {
var name: String
var role: String
var startDate: Date
var endDate: Date
var owner: Owner?
}

Leveraging Swift's macro system, developers can enjoy a streamlined API for modeling data using the familiar Codable protocol.

Persisting a Model

To persist a model instance by SwiftData, insert the instance into the context using the insert function.

var task = Task(name: name, 
role: role,
startDate: startDate,
endDate: endDate)

context.insert(task)

After performing the insert, you have two options for saving the changes. The first option is to explicitly call the save() method on the context immediately. This will persist the changes to the underlying data store.

Alternatively, you can rely on the context's implicit save behavior. Contexts automatically track changes made to their known model instances, and these changes will be included in subsequent saves without requiring explicit invocation of the save() method. The context will take care of persisting the changes to the data store as needed.

Fetching a Model

To fetch instances of a model and optionally apply search criteria and a preferred sort order in your SwiftUI view, you can use the @Query property wrapper. Additionally, by using the @Model macro, you can add Observable conformance to your model classes.

This enables SwiftUI to automatically refresh the containing view whenever changes occur to any of the fetched instances.

import SwiftUI
import SwiftData

struct ContentView: View {
@Query(sort: \.endDate, order: .reverse) var allTasks: [Task]

var body: some View {
List {
ForEach(allTasks) { task in
TaskView(for: task)
}
}
}
}

WidgetKit

This major feature release empowers developers to extend their app's content beyond the app itself. With WidgetKit, developers can create glanceable, up-to-date experiences in the form of widgets, Live Activities, and watch complications.

@main
struct WeatherStatusWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: "",
provider: WeatherStatusProvider()
) { entry in
WeatherStatusView(entry.weatherStatus)
}
.configurationDisplayName("Weather Status")
.description("Shows an overview of your weather status")
.supportedFamilies([.systemSmall])
}
}

The technology and design similarities among widgets, Live Activities, and watch complications facilitate seamless feature development and usage across different contexts.

ActivityKit

ActivityKit offers developers the ability to create Live Activities that provide live updates and interactions directly from their apps. Live Activities can appear in prominent positions such as the Lock Screen, Dynamic Island, and as banners on the Home Screen. Users can view real-time information, launch the app, and perform specific functionalities through buttons and toggles, without fully opening the app.

import SwiftUI
import WidgetKit

@main
struct FoodOrderActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: FoodOrderAttributes.self) { context in

} dynamicIsland: { context in

}
}
}

By leveraging SwiftUI and WidgetKit, developers can share code between widgets and Live Activities, making it easier to build engaging experiences.

Observable

The Observable protocol simplifies the implementation of data change notifications. By attaching the Observable macro to custom types, developers indicate conformance to the Observable protocol. This protocol enables types to emit notifications to observers whenever the underlying data changes.

@Observable final class Animal {
var name: String = ""
var sleeping: Bool = false

init(name: String, sleeping: Bool = false) {
self.name = name
self.sleeping = sleeping
}
}

To enable change tracking, use the withObservationTracking(_:onChange:) function. In the provided code example, this function is used to call the onChange closure when the name property of a car changes. However, it does not trigger the closure when the sleeping flag of the car changes. This behavior occurs because the function only tracks properties that are read within its apply closure, and in this case, the sleeping property is not read within that closure.

func render() {
withObservationTracking {
for animal in animals { //apply closure
print(animal.name)
}
} onChange: { //onChange closure
print("Call UI updation.")
}
}

The Observable protocol provides a convenient way to handle data updates and build reactive interfaces, enhancing the overall user experience of the app.

WorkoutKit

This powerful framework offers models and utilities for creating and previewing workout compositions in iOS and watchOS apps. Developers can design various types of workouts, including CustomWorkoutComposition, GoalWorkoutComposition, and others catering to different fitness activities. The framework provides methods for validating, exporting, and previewing workouts, allowing users to save compositions to the Workout app. Furthermore,

WorkoutKit enables developers to create and manage workout schedules, sync scheduled compositions to Apple Watch, and query completed workouts.

PayLaterView

Showcasing Apple Pay Later Feature Apple Pay Later, a new financial service, received special attention at WWDC 2023. To enhance its visibility, Apple introduced the PayLaterView, a dedicated view for displaying the Apple Pay Later visual merchandising widget.

VisionOS

One of the key features of VisionOS is the ability to create multiple windows within the app. These windows, built using SwiftUI, provide familiar views and controls while enabling developers to add depth by incorporating stunning 3D content. With VisionOS, it is possible to further enhance the app's depth by incorporating 3D volumes.

These volumes, powered by RealityKit or Unity, allows to showcase captivating 3D content that can be viewed from any angle within the Shared Space or an app's Full Space. The flexibility of volumes helps to craft engaging experiences that captivate and delight app users.

By default, apps in VisionOS launch into the Shared Space, where they coexist side-by-side, akin to multiple apps on a Mac desktop. Utilizing windows and volumes, apps can display their content within this shared environment, giving users the ability to freely reposition and interact with these elements. For a truly immersive experience, apps can open a dedicated Full Space, where only their content is visible. Within a Full Space, apps can leverage windows and volumes, create unbounded 3D content, open portals to different worlds, or provide users with a fully immersive environment.

Conclusion

Apple WWDC 2023 brought significant enhancements for developers, offering tools and frameworks to streamline data modeling, extend app content through widgets and Live Activities, simplify data change notifications, optimize workout compositions, and showcase new financial features.

These advancements empower developers to create more immersive and feature-rich applications across Apple's ecosystem of devices.

CREATING A SEAMLESS USER EXPERIENCE IN YOUR IOS APP USING SWIFT

Published: · Last updated: · 5 min read
Appxiom Team
Mobile App Performance Experts

Creating a seamless user experience is an essential aspect of building a successful iOS app. Users expect apps to be fast, responsive, and intuitive.

In this blog post, we'll explore some Swift code examples that can help you create a seamless user experience in your iOS app.

Caching Data Locally in iOS App

One way to improve the performance of your app is to cache data locally. Caching data can reduce the need for repeated network requests, which can improve the speed of your app and create a smoother user experience.

In Swift, you can use the NSCache class to cache data in memory. NSCache is a collection that stores key-value pairs in memory and automatically removes objects when they are no longer needed.

Here's an example of how you can use NSCache to cache data in your app:

let cache = NSCache<NSString, NSData>()

func fetchData(from url: URL, completion: @escaping (Data?) -> Void) {
if let data = cache.object(forKey: url.absoluteString as NSString) {
completion(data as Data)
} else {
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
cache.setObject(data as NSData, forKey: url.absoluteString as NSString)
completion(data)
} else {
completion(nil)
}
}.resume()
}
}

In this example, we create an instance of NSCache and a function called fetchData that retrieves data from a URL. The function first checks if the data is already cached in memory using the cache's object(forKey:) method. If the data is found, the completion handler is called with the cached data. If the data is not found, we use URLSession to retrieve the data from the network. Once the data is retrieved, we cache it in memory using the cache's setObject(_:forKey:) method and call the completion handler with the data.

You can call this fetchData method whenever you need to retrieve data from the network. The first time the method is called for a particular URL, the data will be retrieved from the network and cached in memory. Subsequent calls to the method for the same URL will retrieve the data from the cache instead of the network, improving the performance of your app.

Handling Asynchronous Operations in Swift

Asynchronous operations, such as network requests and image loading, can sometimes cause a delay in your app's responsiveness. To prevent this, you can use asynchronous programming techniques to perform these operations without blocking the main thread.

1. Using closures

In Swift, one way to handle asynchronous operations is to use closures. Closures are blocks of code that can be passed around and executed at a later time. You can use closures to perform asynchronous operations and update the UI once the operation is complete.

Here's an example of how you can use closures to load an image asynchronously and update the UI once the image is loaded:

func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
let image = UIImage(data: data)
completion(image)
} else {
completion(nil)
}
}.resume()
}

In this example, we create a function called loadImage that loads an image from a URL. We use URLSession to retrieve the image data from the network. Once the data is retrieved, we create a UIImage object from the data and call the completion handler with the image. If there is an error retrieving the image data, we call the completion handler with nil.

You can call this loadImage method whenever you need to load an image asynchronously in your app. The completion handler allows you to update the UI with the loaded image once it's available.

2. Using DispatchQueue

Another way to handle asynchronous operations in Swift is by using the DispatchQueue class. DispatchQueue is a class that provides a way to perform work asynchronously on a background queue.

Here's an example of how you can use DispatchQueue to perform work on a background thread:

DispatchQueue.global().async {
// Perform background work hereDispatchQueue.main.async {
// Update the UI on the main thread
}
}

In this example, we use the global() method of DispatchQueue to get a reference to the global background queue. We call the async method to perform work asynchronously on the background queue. Once the work is complete, we use the main method of DispatchQueue to switch back to the main thread and update the UI.

You can use DispatchQueue to perform any work that doesn't need to be done on the main thread, such as data processing or database queries. By using a background thread, you can prevent the main thread from becoming blocked, which can improve the responsiveness of your app.

Using Animations in Swift

Animations can make your app feel more polished and responsive. In Swift, you can use the UIView.animate(withDuration:animations:) method to perform animations.

Here's an example of how you can use UIView.animate(withDuration:animations:) to fade in a view:

UIView.animate(withDuration: 0.5) {
view.alpha = 1.0
}

In this example, we use the animate(withDuration:animations:) method to animate the alpha property of a view. We specify a duration of 0.5 seconds for the animation. Inside the animation block, we set the alpha property of the view to 1.0, which will cause the view to fade in over 0.5 seconds.

You can use UIView.animate(withDuration:animations:) to animate any property of a view, such as its position or size. Animations can make your app feel more alive and responsive, which can improve the user experience.

Conclusion

Creating a seamless user experience is an essential aspect of building a successful iOS app. In this blog post, we explored some Swift code examples that can help you create a seamless user experience in your app.

We discussed caching data locally, handling asynchronous operations, and using animations. By using these techniques in your app, you can improve its performance, responsiveness, and polish, which can lead to happier users and a more successful app.

ANALYSIS OF IMPACT OF BUGS IN ANDROID, IOS AND WATCHOS APPS IS NOW AVAILABLE IN APPXIOM.

Published: · Last updated: · One min read
Appxiom Team
Mobile App Performance Experts

Performance Analytics has been a demand from our customers since Appxiom 1.0. Now with the release of Appxiom 6.0 the mobile app developers will get a clear understanding about how the bugs are impacting the installation base. The data is presented graphically and provides insights into the percentage and absolute number of android, watchOS and iOS devices that got affected.

Fig 1: Analysis of bugs and the impact on mobilesThe impact of memory leaks, abnormal memory usages, slow frames and frozen frames, ANR and App Hang, UI thread blocks, network issues, and all other bugs are now presented in a tangible way. Also bugs can be ordered based on the number of devices that are affected. This helps mobile app developers to prioritise bugs and to understand where they need to focus on to improve the performance of the app.

Appxiom 6.0 comes as Android SDK, iOS framework and watchOS framework. It's currently in closed beta, and is expected to go live by 21st of February, 2022. If you would like to request access for Appxiom 6.0, click here.