SwiftCloudDrive - An easy to use Swift wrapper around iCloud Drive.

Overview

SwiftCloudDrive

Author: Drew McCormack (@drewmccormack)

An easy to use Swift wrapper around iCloud Drive.

SwiftCloudDrive handles complexities like file coordination, file conflicts, and cloud metadata queries, to provide straightforward async functions for working with files in iCloud. It makes handling files in the cloud almost as easy as working locally with FileManager.

When is SwiftCloudDrive a Good Solution?

For advanced uses of iCloud, you should probably use Apple's frameworks directly. This gives you most control, in exchange for a steep learning curve.

For example, if you need complete control over when files in iCloud Drive get downloaded to a device, or have an app like Apple's Photos, where it is often desirable to leave files in the cloud until they are requested by the user, you should not use SwiftCloudDrive.

If you want all of your app's iCloud Drive files on device, as well as in the cloud, SwiftCloudDrive can get you up and running much faster. You don't have to worry about file coordination, metadata queries, or conflict resolution, which are all part of working with iCloud Drive. SwiftCloudDrive will give you a simple class to upload, download, query, and update, which works much the same as the FileManager type you are already familiar with.

Using SwiftCloudDrive

Integrating the Package

To get started, add the SwiftCloudDrive package to your Xcode project, and then enable iCloud Drive in the Signing & Capabilities tab of your app's target in Xcode. You can accept the default container identifier, or choose a custom one.

Setting Up a Drive

If you are using the default iCloud container, setting up a CloudDrive in your app's source code can be as simple as this

import SwiftCloudDrive
let drive = CloudDrive()

If you have a custom iCloud container, simply pass the identifier in.

let customDrive = CloudDrive(ubiquityContainerIdentifier: "iCloud.com.yourcompany.app")

In the cases above, you will be accessing files directly in the root of the container, but you can also anchor your CloudDrive at a particular subdirectory of the container, like this

let subDrive = CloudDrive(relativePathToRootInContainer: "Sub/Directory/Of/Choice")

The CloudDrive will create the root directory for you, if it doesn't exist.

Querying File Status

Once you have a CloudDrive object, you can query file status just like you do with FileManager. There is one big difference though: because files may be remote and have to download, all function calls are async.

To determine if a directory exists, you would do this

let path = RootRelativePath(path: "Path/To/Dir")
let exists = try await drive.directoryExists(at: path)

If you want to know if a particular file exists, you would use this

let exists = try await drive.fileExists(at: path)

Working with Paths

As you can see in the previous section, the RootRelativePath struct is used to reference paths relative to the root of the CloudDrive.

If you use particular fixed paths often, it is useful to extend RootRelativePath to define static constants.

extension RootRelativePath {
    static let images = Self(path: "Images")
}

let imagesExist = try await drive.directoryExists(at: .images)
let dogImageExists = try await drive.fileExists(at: .images.appending("Dog.jpeg"))

As you can see, the RootRelativePath also defines an appending function which makes it simple to extend an existing path.

Creating Directories

Creating a directory in the cloud is just as easy. Note that if there are missing intermediate directories, these are always created too.

try await drive.createDirectory(at: .images)

Uploading and Downloading Files

To move files into the cloud, you can 'upload' a local file to the container, or you can write Data directly into a file.

let data = "Some text".data(using: .utf8)!
try await drive.writeFile(with: data, at: .root.appending("file.txt"))

In this case we use the built in static constant root to build a path, but we could also have just used RootRelativePath("file.txt").

To upload a file from outside of the cloud container, you use code like this

try await drive.upload(from: "/Users/eddy/Desktop/image.jpeg", to: .images.appending("image.jpeg"))

Updating Files

Once you have a file in the cloud, you can change it by uploading again, but you must first delete the old version, otherwise an error will arise.

let cloudPath: RootRelativePath = .images.appending("image.jpeg")
try? await drive.removeFile(at: cloudPath)
try await drive.upload(from: "/Users/eddy/Desktop/image_new.jpeg", to: cloudPath)

Alternatively, you can write the contents without first removing the existing file.

try await drive.writeFile(with: newImageData, at: cloudPath)

If you need even finer control, you can make any in-place update you favor, like this

try await drive.updateFile(at: imagePath) { fileURL in
    // Make any changes you like to the file at `fileURL`
    // You can also throw an error
}

Removing Files and Directories

As we have already seen, you can very easily remove files and directories.

try await drive.removeFile(at: cloudFilePath)
try await drive.removeDirectory(at: cloudDirPath)

If the wrong type of item is encountered, the removal fails and an error is thrown.

Observing Remote Changes

When working with changes on remote devices, it is important to know when new files have downloaded, or updates have been applied. You can register a CloudDriveObserver for this purpose.

class Controller: CloudDriveObserver {
    func cloudDriveDidChange(rootRelativePaths: [RootRelativePath]) {
        // Decide if data needs refetching due to remote changes,
        // or if changes need to be applied in the UI
    }
}

let controller = Controller()
drive.observer = controller

Note that the relative paths passed to the observer are not necessarily new files, but could be files with updates, or even files that were removed. Your code should take these possibilities into account, and adapt appropriately.

You might also like...
Wanikani-swift - Unofficial Swift client for the WaniKani API

WaniKani A Swift library and client for the WaniKani REST API. It currently supp

 AWS Full Stack Swift with Apple CarPlay
AWS Full Stack Swift with Apple CarPlay

This application demonstrates a full-stack Apple CarPlay app that uses Swift for both the UI and the backend services in AWS. The app accesses Lambda functions written in Swift and deployed from Docker images. The app accesses Amazon Location Service and a 3rd party weather api to display information in the vicinity of the user.

Unofficial GitHub API client in Swift
Unofficial GitHub API client in Swift

Github.swift ❤️ Support my apps ❤️ Push Hero - pure Swift native macOS application to test push notifications PastePal - Pasteboard, note and shortcut

A swift SDK for Medium's OAuth2 API

Medium SDK - Swift A library to allow access to Medium API for any Swift iOS application. Features Medium.com authorization & token handling Login sta

A Twitter framework for iOS & OS X written in Swift
A Twitter framework for iOS & OS X written in Swift

Getting Started Installation If you're using Xcode 6 and above, Swifter can be installed by simply dragging the Swifter Xcode project into your own pr

Build Slack apps, in Swift
Build Slack apps, in Swift

SlackKit: Slack Apps in Swift Description SlackKit makes it easy to build Slack apps in Swift. It's intended to expose all of the functionality of Sla

👤 Framework to Generate Random Users - An Unofficial Swift SDK for randomuser.me
👤 Framework to Generate Random Users - An Unofficial Swift SDK for randomuser.me

RandomUserSwift is an easy to use Swift framework that provides the ability to generate random users and their accompanying data for your Swift applic

Swift 3 framework for accessing data in Event Registry (http://eventregistry.org/)

PPEventRegistryAPI Swift 3 framework for accessing data in Event Registry (http://eventregistry.org/) Supported API calls Log In Get Event By Identifi

Swift client for Unsplash
Swift client for Unsplash

Unsplash API client written in Swift. Unsplash offers 2 APIs: Source API (unlimited requests) Official API JSON API (5000 requests / hour) JSON API is

Owner
Drew McCormack
agenda.com, studiesapp.com, ensembles.io
Drew McCormack
A Swift wrapper for Foursquare API. iOS and OSX.

Das Quadrat Das Quadrat is Foursquare API wrapper written in Swift. Features Supports iOS and OSX. Covers all API endpoints. Authorization process imp

Constantine Fry 171 Jun 18, 2022
Pokeapi wrapper, written in Swift

PokemonKit What is this? PokemonKit is a swift wrapper for Pokeapi. PokemonKit use Alamofire and PromiseKit for async web requests handling. Usage imp

Continuous Learning 105 Nov 16, 2022
Swift Wrapper For Bittrex API

BittrexApiKit Swift client for Bittrex api. It support all APIs with most recent changes. more info here let api = Bittrex(apikey: "api key", secretke

Saeid 8 Apr 5, 2021
Unofficial Dribbble iOS wrapper allows you to integrate Dribble API into iOS application (Designer, Shot, Comment, User Story, Like, Follow)

DribbbleSDK DribbbleSDK is easy-to-use iOS wrapper for Dribbble SDK. We're working hard to complete the full coverage of available methods and make th

Agilie Team 74 Dec 2, 2020
An API wrapper for bitFlyer.

SwiftFlyer An API wrapper for bitFlyer that supports all providing API. API Document https://lightning.bitflyer.jp/docs Usage Public API Fetch a marke

Ryo Ishikawa 39 Nov 3, 2022
The best way to use the Zora API in your Swift projects.

ZoraKit The best way to use the Zora API in your Swift projects. Disclaimer This is still very much a work in progress, and is really a proof-of-conce

MBLA 6 Sep 23, 2022
The Easiest and Simplest iOS library for Twitter and Facebook. Just Drop in and Use!

EasySocial iOS Library for Twitter and Facebook This library allows your apps to use Twitter and Facebook with minimal understanding of the relevant S

pj 124 Nov 17, 2022
A clima based app with use of API

Clima Our Goal It’s time to take our app development skills to the next level. We’re going to introduce you to the wonderful world of Application Prog

null 0 Nov 28, 2021
Easy and powerful way to interact with VK API for iOS and macOS

Easy and powerful way to interact with VK API for iOS and macOS. Key features ?? It's not ios-vk-sdk ?? ?? One library for iOS and mac OS ?? ?? Fully

null 260 Dec 22, 2022
Easy Proximity-based Bluetooth LE Sharing for iOS

Description Easy Proximity-based Sharing for iOS Perfect for any iOS app that needs to quickly share items with nearby friends, such as groups, photo

Laura Skelton 132 Aug 10, 2022