withUnsafeBytes والتكامل مع C
اربط بواجهات C التي تتوقع بايتات خامًا.
withUnsafeBytes والتكامل مع C درس مجاني في Swift Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Swift Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Swift Academy 4 دروس في المجموع.
من الأنواع المحددة إلى البايتات الخام
قد تحتاجون أحيانًا إلى رؤية قيمة لا بصفتها Int أو struct، بل كسلسلة من البايتات الخام — من أجل تجزئتها، أو كتابتها في ملف، أو تمريرها إلى واجهة C. يوفر لكم withUnsafeBytes ذلك تحديدًا: عرضًا مؤقتًا لمساحة تخزين قيمة ما بصفتها UInt8.
var value: UInt32 = 0x01020304
withUnsafeBytes(of: &value) { rawBuffer in
print(rawBuffer.count) // 4 bytes
}مؤشر مخزن البايتات الخام غير الآمن
تتلقى closure قيمة UnsafeRawBufferPointer — وهي مخزن من البايتات بلا نوع عناصر. تستخدمون الفهرسة لقراءة قيم UInt8 الفردية. وهو للقراءة فقط؛ أما الصيغة القابلة للتعديل فهي withUnsafeMutableBytes.
var value: UInt32 = 0x01020304
withUnsafeBytes(of: &value) { bytes in
for b in bytes { print(String(format: "%02x", b)) }
}
// Order depends on endiannessترتيب البايتات مهم
يعتمد ترتيب البايتات الذي تلاحظونه على ترتيب البايتات في المنصة. في الأجهزة ذات الترتيب little-endian، مثل Apple silicon وIntel، يأتي البايت الأقل أهمية أولًا. عند إجراء التسلسل من أجل بروتوكول، حوّلوا الترتيب صراحةً باستخدام bigEndian أو littleEndian.
let host: UInt32 = 0x01020304
let networkOrder = host.bigEndian
var be = networkOrder
withUnsafeBytes(of: &be) { bytes in
// Always 01 02 03 04 regardless of platform
print(Array(bytes))
}بايتات البنية
تعمل withUnsafeBytes(of:) مع أي قيمة، بما في ذلك البنى. يساوي طول المخزن المؤقت MemoryLayout<T>.size، وتُضمَّن أي بايتات حشو، لكن محتوياتها غير محددة.
struct RGB { var r: UInt8; var g: UInt8; var b: UInt8 }
var color = RGB(r: 255, g: 128, b: 0)
withUnsafeBytes(of: &color) { bytes in
print(bytes[0], bytes[1], bytes[2]) // 255 128 0
}تحميل قيمة من البايتات
لإعادة تفسير البايتات الخام على أنها قيمة ذات نوع محدد، استخدموا load(fromByteOffset:as:) على مخزن خام. يجب أن يحترم الإزاحة محاذاة النوع، ويجب أن تمثل البايتات فعليًا قيمة صالحة من ذلك النوع.
let raw: [UInt8] = [0x04, 0x03, 0x02, 0x01]
let n = raw.withUnsafeBytes { ptr in
ptr.load(fromByteOffset: 0, as: UInt32.self)
}
print(String(format: "0x%08x", n))استخدام loadUnaligned للبيانات المضغوطة
غالبًا ما تضغط التنسيقات الثنائية الحقول من دون حشو للمحاذاة. يؤدي استدعاء load عند إزاحة غير محاذاة إلى سلوك غير محدد؛ لذا استخدموا loadUnaligned(fromByteOffset:as:) للقراءة بأمان من أي إزاحة.
let packet: [UInt8] = [0xFF, 0x04, 0x03, 0x02, 0x01]
let field = packet.withUnsafeBytes { ptr in
ptr.loadUnaligned(fromByteOffset: 1, as: UInt32.self)
}
print(field)ربط Swift Data بـ C
تقبل العديد من دوال C قيمة const void * بالإضافة إلى طول. تعرض Data والمصفوفات withUnsafeBytes، بحيث يمكنكم تمرير baseAddress وcount مباشرةً من دون نسخ.
import Foundation
let data = Data([0x68, 0x69]) // "hi"
data.withUnsafeBytes { (raw: UnsafeRawBufferPointer) in
if let base = raw.baseAddress {
// c_consume(base, raw.count)
print("ptr", base, "len", raw.count)
}
}استلام مؤشر C
عندما تمرر لكم callback في C قيمة const void * وطولًا، غلّفوها في UnsafeRawBufferPointer للتكرار بأمان. ستستورد Swift مؤشر C على أنه UnsafeRawPointer?.
func handleC(_ ptr: UnsafeRawPointer, _ len: Int) {
let buffer = UnsafeRawBufferPointer(start: ptr, count: len)
let checksum = buffer.reduce(0) { $0 &+ Int($1) }
print("checksum:", checksum)
}استخدام bindMemory وإعادة التفسير
لمعاملة منطقة خام على أنها عناصر ذات نوع محدد، يخبر bindMemory(to:capacity:) المترجم بكيفية تفسيرها. يؤدي إساءة استخدام ذلك، أي ربط الذاكرة نفسها بنوعين غير متوافقين، إلى انتهاك قواعد Swift الصارمة للتعرية ويؤدي إلى سلوك غير محدد.
let raw = UnsafeMutableRawPointer.allocate(
byteCount: 8, alignment: 8)
defer { raw.deallocate() }
let typed = raw.bindMemory(to: Int.self, capacity: 1)
typed.pointee = 1234
print(typed.pointee)الفرق بين assumingMemoryBound وbindMemory
يغيّر bindMemory طريقة تفسير الذاكرة تغييرًا دائمًا، بينما يؤكد assumingMemoryBound(to:) أنها مرتبطة بالفعل بذلك النوع من دون تغيير أي شيء. استخدموا الأخير فقط عندما تكونون متأكدين من الربط الموجود، مثل الذاكرة التي تعرفون أنها تحتوي على النوع المحدد.
func sumInts(_ raw: UnsafeRawPointer, _ count: Int) -> Int {
let p = raw.assumingMemoryBound(to: Int.self)
var total = 0
for i in 0..<count { total += p[i] }
return total
}قائمة التحقق من الأمان
تختبئ معظم حالات التعطل في التعامل مع البايتات الخام والتكامل مع C. تذكروا ما يلي:
- لا تسمحوا أبدًا بخروج مؤشر closure إلى خارجها.
- احترموا المحاذاة أو استخدموا صيغ
Unaligned. - تعاملوا مع
endiannessصراحةً عند إجراء التسلسل. - لا تعيدوا ربط الذاكرة بأنواع متعارضة.
- تحققوا من
nilفيbaseAddressعند التعامل مع المخازن المؤقتة الفارغة.
// Convert any value to a hex string safely
import Foundation
func hex<T>(_ v: T) -> String {
var value = v
return withUnsafeBytes(of: &value) { bytes in
bytes.map { String(format: "%02x", $0) }.joined()
}
}اختبار سريع
اختبروا مدى فهمكم لقراءة البيانات الثنائية المضغوطة.
مراجعة
تعلمتم كيفية الربط بين قيم Swift وC من خلال البايتات الخام:
- تعرض
withUnsafeBytes(of:)أي قيمة بصفتهاUInt8. - تعيد
load/loadUnalignedتفسير البايتات كقيم ذات أنواع محددة مع احترام المحاذاة. - تعرض
DataوالمصفوفاتwithUnsafeBytesلتمرير مؤشر + طول إلى C. - يتحكم
bindMemoryوassumingMemoryBoundفي كيفية تحديد نوع الذاكرة الخام. - يُعد ترتيب البايتات والمحاذاة وخروج المؤشر من النطاق أهم مصادر الخطر.
الأسئلة الشائعة
هل درس «withUnsafeBytes والتكامل مع C» مجاني؟
نعم — نص درس «withUnsafeBytes والتكامل مع C» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Swift Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Swift Academy 4 دروس في المجموع.
ماذا ستتعلم في «withUnsafeBytes والتكامل مع C»؟
اربط بواجهات C التي تتوقع بايتات خامًا. تتمرن على Swift Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Swift Academy؟
لا تُشترط خبرة سابقة. Swift Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «withUnsafeBytes والتكامل مع C»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Swift Academy هذا؟
نعم. كل درس في Swift Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- MemoryLayout والمحاذاة
- UnsafePointer و UnsafeMutablePointer
- مؤشرات المخازن المؤقتة غير الآمنة
- withUnsafeBytes والتكامل مع C