مقدمة: لماذا يحتاج مطور iOS/macOS إلى WebAssembly؟
WebAssembly (Wasm) هو تنسيق تعليمات ثنائي تم إنشاؤه في الأصل للمتصفحات، لكنه سرعان ما وجد تطبيقات في التطوير الأصلي. لمطوري Swift على iOS وmacOS، يفتح دمج WebAssembly إمكانيات فريدة: يمكنك إعادة استخدام كود عالي الأداء بلغات C/C++ أو Rust أو Go دون إعادة كتابته بلغة Swift، وتشغيله بسرعة تقارب السرعة الأصلية. هذا مهم بشكل خاص للعمل مع الرسومات والتشفير والمحاكاة والخوارزميات المعقدة.
في هذه المقالة، سنشرح كيفية تجميع الكود إلى Wasm، ودمجه في مشروع Swift لنظامي iOS/macOS، ونقل البيانات ومعالجة الأخطاء. جميع الأمثلة مكتوبة بلغة Swift 5.9+ وموجهة لـ Xcode 15+.
1. تجميع الكود إلى WebAssembly لمشروع Swift
الخطوة الأولى هي الحصول على وحدة Wasm. الطريقة الأكثر شيوعًا هي تجميع كود C/C++ باستخدام Emscripten أو WasmEdge. لنلق نظرة على مثال بلغة C.
أنشئ ملفًا باسم math_ops.c:
// math_ops.c#include <emscripten.h>
EMSCRIPTEN_KEEPALIVEint add(int a, int b) { return a + b;}
EMSCRIPTEN_KEEPALIVEdouble multiply(double a, double b) { return a * b;}
EMSCRIPTEN_KEEPALIVEint factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1);}قم بتجميعه إلى Wasm باستخدام Emscripten (قم بتثبيته عبر Homebrew: brew install emscripten):
emcc math_ops.c -o math_ops.wasm -s WASM=1 -s EXPORTED_FUNCTIONS='["_add", "_multiply", "_factorial"]' -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -O3ستحصل على ملف math_ops.wasm و math_ops.js (لن نحتاج إلى الغلاف js، سنعمل مباشرة مع Wasm).
2. دمج وحدة Wasm في Swift (iOS/macOS)
للعمل مع WebAssembly في Swift الأصلي، سنستخدم إطار العمل WasmKit أو SwiftWasm. نوصي باستخدام WasmKit الذي يدعم iOS 15+ وmacOS 12+.
2.1. تثبيت WasmKit عبر Swift Package Manager
أضف التبعية في Package.swift أو عبر Xcode: File → Add Packages → https://github.com/swiftwasm/WasmKit.
2.2. تحميل وتنفيذ وحدة Wasm
أنشئ ملف Swift باسم WasmEngine.swift:
import WasmKitimport Foundation
class WasmEngine { private var instance: Instance? private var store: Store? /// تحميل وحدة Wasm من ملف func loadModule(from url: URL) throws { let data = try Data(contentsOf: url) let module = try Module(data: data) let engine = Engine() store = Store(engine: engine) let imports = Imports() // هنا يمكن إضافة استيراد دوال من Swift (انظر القسم 3) instance = try Instance(module: module, imports: imports, store: store!) } /// استدعاء دالة مُصدّرة func callFunction(_ name: String, args: [Value]) throws -> [Value] { guard let instance = instance else { throw WasmError.moduleNotLoaded } let function = instance.exports[name] as! Function return try function(args) }}
enum WasmError: Error { case moduleNotLoaded case functionNotFound}2.3. الاستخدام في تطبيق SwiftUI
import SwiftUI
struct ContentView: View { @State private var result: String = "0" private let engine = WasmEngine() var body: some View { VStack(spacing: 20) { Text("النتيجة: \\(result)") .font(.title) Button("حساب مضروب 5") { do { let wasmURL = Bundle.main.url(forResource: "math_ops", withExtension: "wasm")! }