
Pada 2014, Swift diperkenalkan, bahasa baru untuk mengembangkan aplikasi ekosistem Apple. Kebaruan membawa tidak hanya fitur dan fungsi baru, tetapi juga masalah - bagi mereka yang ingin menggunakan perpustakaan-C tua yang baik. Pada artikel ini, saya akan membahas salah satunya - bundling C-library dalam kerangka Swift. Ada beberapa cara untuk menyelesaikannya; dalam hal ini, saya akan menjelaskan bagaimana melakukan ini dengan modul eksplisit dentang.
Sebagai contoh, kami mengambil
libgif C-library eksternal dan menanamkannya dalam kerangka kerja Swift GifSwift kami. Jika Anda ingin segera melihat hasilnya, proyek lengkap dapat dilihat di
sini .
Mempersiapkan libgif
Sebelum menyematkan pustaka libgif di proyek kami, Anda harus mengompilasinya dari sumber.
- Unduh tarball terbaru di sini .
- Buka kemasan arsip, gunakan konsol, buka folder dan jalankan:
./configure && make check
Catatan: untuk kesederhanaan, kami sedang menyusun pustaka untuk platform x86-64, dan karena itu hanya akan berfungsi di simulator iOS atau di macOS. Membangun perpustakaan statis multi-arsitektur adalah topik terpisah, yang tidak saya sentuh dalam artikel ini. Instruksi yang berguna dapat ditemukan di sini .
- Jika semua berjalan tanpa kesalahan, file perpustakaan dapat ditemukan di
${lib_gif_source}/lib/.libs
. Kami tertarik pada dua file:
lib/.libs/libgif.a # lib/gif_lib.h #
Penyiapan proyek
Sekarang kami akan menyesuaikan proyek dengan kebutuhan kami.
- Buat proyek baru menggunakan template Cocoa Touch Framework, beri nama GifSwift .
- Tambahkan file perpustakaan libgif yang kami buat ke grup terpisah di dalam proyek.
- Tambahkan target baru untuk aplikasi uji ke proyek untuk melihat hasilnya.
Struktur akhir dari proyek akan terlihat seperti ini:

Impor ke Swift
Untuk mengimpor perpustakaan-C ke Swift, kita harus menggambarkannya sebagai
modul . Deskripsi adalah file
.modulemap yang berisi daftar file header untuk impor dan perpustakaan statis untuk ditautkan. Modul yang dihasilkan dapat diimpor ke kode Swift atau Objective-C (menggunakan
@import
).
Metode ini mengimpor perpustakaan ke dalam kerangka kerja akan bekerja dalam banyak kasus (baca lebih lanjut tentang pendekatan ini di
sini ). Ini berfungsi baik jika Anda membuat kerangka kerja internal atau hanya memecah aplikasi Anda menjadi modul. Tetapi metode ini juga memiliki kekurangan. Sebagai contoh, itu tidak efektif jika Anda ingin mentransfer perpustakaan Anda ke seseorang menggunakan Carthage, Cocoapods atau karena artefak biner. Alasannya adalah bahwa kerangka kerja yang dihasilkan umumnya tidak portabel, karena ketika mengkompilasinya terikat ke lokasi tertentu dari file header dan pustaka dari peta modul di komputer Anda.
Modul Eksplisit
Untuk mengatasi keterbatasan ini, kami akan menggunakan cara lain - modul
eksplisit untuk perpustakaan. Modul eksplisit adalah modul yang dinyatakan sebagai submodule menggunakan kata kunci
eksplisit , ditempatkan di modul induk, dan
tidak secara otomatis
diimpor . Ia bekerja mirip dengan
*_Private.h
untuk kerangka kerja Objective-C. Jika Anda ingin menggunakan API yang dideklarasikan di dalamnya, Anda harus mengimpor modul
secara eksplisit (eksplisit).Kami membuat modul eksplisit untuk C-library di dalam kerangka kerja. Untuk melakukan ini, kita perlu mendefinisikan kembali modul Xcode yang dihasilkan. Juga, perhatikan bahwa kami tidak menentukan pustaka libgif.a untuk tautan (tautan gif), tetapi melakukannya secara langsung dalam proyek menggunakan antarmuka Xcode.
Catatan: untuk mempelajari lebih lanjut tentang modul eksplisit , klik di sini.- Tambahkan file bernama GifSwift.modulemap ke folder root proyek:
framework module GifSwift { umbrella header "GifSwift.h" explicit module CLibgif { private header "gif_lib.h" } export * }
File ini berisi spesifikasi untuk modul CLibgif eksplisit dan terdiri dari satu file header yang dideklarasikan (karena hanya ada satu di perpustakaan kami). File dimuat ke modul yang dihasilkan untuk kerangka kerja.
- File deskripsi modul tidak perlu ditambahkan ke kerangka kerja, tetapi harus ditentukan dalam pengaturan target:
Build Settings — Packaging — Module Map (MODULEMAP_FILE) = $SRCROOT/GifSwift/GifSwift.modulemap
- file libgif harus ditambahkan ke target kerangka kerja sebagai header pribadi ( gif_lib.h ) dan perpustakaan statis ( libgif.a ). Harap perhatikan bahwa file header untuk pustaka C telah ditambahkan ke target sebagai pribadi. Ini diperlukan untuk modul eksplisit kami. Tidak ada yang mencegah menambahkan file header ini sebagai publik, tetapi tugas kami adalah menyembunyikan detail implementasi sesederhana mungkin.

- Sekarang Anda dapat mengimpor modul eksplisit di dalam kerangka kerja menggunakan
import GifSwift.CLibgif
Pembungkus cepat
Sekarang Anda dapat melakukan antarmuka kerangka kerja kami. Satu kelas sudah cukup, yaitu gif dengan beberapa properti:
import Foundation import GifSwift.CLibgif public class GifFile { private let path: URL private let fileHandlePtr: UnsafeMutablePointer<GifFileType> private var fileHandle: GifFileType { return self.fileHandlePtr.pointee } deinit { DGifCloseFile(self.fileHandlePtr, nil) } // MARK: - API public init?(path: URL) { self.path = path let errorCode = UnsafeMutablePointer<Int32>.allocate(capacity: 1) if let handle = path.path.withCString({ DGifOpenFileName($0, errorCode) }) { self.fileHandlePtr = handle DGifSlurp(handle) } else { debugPrint("Error opening file \(errorCode.pointee)") return nil } } public var size: CGSize { return CGSize(width: Double(fileHandle.SWidth), height: Double(fileHandle.SHeight)) } public var imagesCount: Int { return Int(fileHandle.ImageCount) } }
GifFile.swift
membungkus antarmuka pemrograman tingkat rendah untuk memproses file dan mengakses beberapa properti, memetakannya ke tipe Foundation yang lebih nyaman.
Periksa
Untuk menguji perpustakaan kami, saya menambahkan file
cat.gif ke proyek:
import UIKit import GifSwift class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() if let file = GifFile(path: Bundle.main.url(forResource: "cat", withExtension: "gif")!) { debugPrint("Image has size: \(file.size) and contains \(file.imagesCount) images") } } }
Ketika kita menjalankan kode ini di konsol, kita akan melihat yang berikut:
" Gambar memiliki ukuran: (250.0, 208.0) dan berisi 44 gambar"
Kesimpulan
Kerangka kerja yang dihasilkan berisi semua yang perlu Anda gunakan, memiliki antarmuka Swift dan, secara default, menyembunyikan kode C dari klien. Namun, ini tidak sepenuhnya benar. Seperti yang saya tulis di atas, mengimpor
GifSwift.CLibgif memberi Anda akses ke semua modul pribadi, namun, secara default, metode enkapsulasi ini cukup untuk menyembunyikan detail implementasi kerangka kerja.