Working with ZIP/archives in Swift (iOS/macOS): a complete guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Working with ZIP/archives in Swift (iOS/macOS)

In modern iOS and macOS development, there is often a need to package and unpackage files. ZIP archives are a standard data compression method supported on all Apple platforms. In this article, we will look at native Swift tools for working with ZIP, as well as the popular library ZIPFoundation.



Native Foundation tools

The Foundation framework provides basic capabilities for working with archives through the NSFileCoordinator class and system utilities. However, for full-fledged work with ZIP, it is recommended to use third-party libraries or wrappers over system commands.



ZIPFoundation library

ZIPFoundation is a lightweight library for working with ZIP archives, written in pure Swift. It supports iOS, macOS, tvOS, and watchOS, requires no external dependencies, and is distributed under the MIT license.



Installation via Swift Package Manager

Add the dependency to Package.swift:

dependencies: [    .package(url: "https://github.com/weichsel/ZIPFoundation.git", from: "0.9.16")]

Or via Xcode: File → Add Packages → enter the repository URL.



Basic operations



1. Creating a ZIP archive

Packaging a single file:

import ZIPFoundation

let fileManager = FileManager.defaultlet sourceURL = URL(fileURLWithPath: "/path/to/file.txt")let destinationURL = URL(fileURLWithPath: "/path/to/archive.zip")

do { try fileManager.zipItem(at: sourceURL, to: destinationURL) print("Archive created: \\(destinationURL.path)")} catch { print("Error: \\(error.localizedDescription)")}


Packaging an entire directory:

let directoryURL = URL(fileURLWithPath: "/path/to/folder")let archiveURL = URL(fileURLWithPath: "/path/to/folder.zip")

do { try fileManager.zipItem(at: directoryURL, to: archiveURL) print("Directory packaged")} catch { print("Error: \\(error)")}


2. Extracting an archive

let archiveURL = URL(fileURLWithPath: "/path/to/archive.zip")let destinationURL = URL(fileURLWithPath: "/path/to/unzip")

do { try fileManager.unzipItem(at: archiveURL, to: destinationURL) print("Extraction complete")} catch { print("Extraction error: \\(error)")}


3. Working with archive contents without extraction

guard let archive = Archive(url: archiveURL, accessMode: .read) else {    fatalError("Failed to open archive")}

// List all entriesfor entry in archive { print("File: \\(entry.path), size: \\(entry.uncompressedSize) bytes")}

// Reading a specific fileif let entry = archive["documents/report.pdf"] { var data = Data() do { _ = try archive.extract(entry, bufferSize: 4096) { partialData in data.append(partialData) } print("Extracted \\(data.count) bytes") } catch { print("Error: \\(error)") }}


4. Adding files to an existing archive

guard let archive = Archive(url: archiveURL, accessMode: .update) else {    fatalError("Failed to open archive for update")}

let newFileURL = URL(fileURLWithPath: "/path/to/new_file.txt")do { try archive.addEntry(with: "new_file.txt", relativeTo: newFileURL.deletingLastPathComponent()) print("File added")} catch { print("Error: \\(error)")}


Working with progress and large files

For large archives, use Progress:

let progress = Progress(totalUnitCount: 100)let archiveURL = URL(fileURLWithPath: "/path/to/large.zip")let destinationURL = URL(fileURLWithPath: "/path/to/output")

do { try FileManager.default.unzipItem(at: archiveURL, to: destinationURL, progress

Recommendations