দ্রষ্টব্য: কোডটি এখন সুইফ্ট 5 (এক্সকোড 10.2) এর জন্য আপডেট করা হয়েছে । (সম্পাদনা ইতিহাসে সুইফ্ট 3 এবং সুইফ্ট 4.2 সংস্করণগুলি পাওয়া যাবে)) সম্ভবত স্বাক্ষরবিহীন ডেটা এখন সঠিকভাবে পরিচালিত হয়েছে।
কিভাবে Data
একটি মান থেকে তৈরি করতে
সুইফট ৪.২ অনুসারে, কেবলমাত্র একটি মান থেকে ডেটা তৈরি করা যায়
let value = 42.13
let data = withUnsafeBytes(of: value) { Data($0) }
print(data as NSData)
ব্যাখ্যা:
withUnsafeBytes(of: value)
মানের কাঁচা বাইটগুলি coveringেকে একটি বাফার পয়েন্টার সহ বন্ধের অনুরোধ জানায়।
- একটি কাঁচা বাফার পয়েন্টার বাইটের ক্রম, তাই
Data($0)
ডেটা তৈরি করতে ব্যবহার করা যেতে পারে।
কীভাবে একটি মান পুনরুদ্ধার করবেন Data
সুইফট 5, এর মতো withUnsafeBytes(_:)
এর Data
পূজা একটি "untyped" সঙ্গে অবসান UnsafeMutableRawBufferPointer
বাইট। load(fromByteOffset:as:)
পদ্ধতি স্মৃতি থেকে মান লেখা আছে:
let data = Data([0x71, 0x3d, 0x0a, 0xd7, 0xa3, 0x10, 0x45, 0x40])
let value = data.withUnsafeBytes {
$0.load(as: Double.self)
}
print(value)
এই পদ্ধতির সাথে একটি সমস্যা রয়েছে: এটির জন্য প্রয়োজন যে মেমরিটি এমন ধরণের জন্য প্রান্তিক সম্পত্তি (এখানে: একটি 8-বাইট ঠিকানায় প্রান্তিক)। তবে এটি গ্যারান্টিযুক্ত নয়, উদাহরণস্বরূপ যদি ডেটা অন্য কোনও Data
মানের টুকরা হিসাবে প্রাপ্ত হয়েছিল obtained
বাইটসটি মানটিতে অনুলিপি করা তাই নিরাপদ :
let data = Data([0x71, 0x3d, 0x0a, 0xd7, 0xa3, 0x10, 0x45, 0x40])
var value = 0.0
let bytesCopied = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
assert(bytesCopied == MemoryLayout.size(ofValue: value))
print(value)
ব্যাখ্যা:
এর রিটার্ন মান copyBytes()
হ'ল অনুলিপি করা বাইটের সংখ্যা। এটি গন্তব্য বাফারের আকারের সমান বা ডেটাতে পর্যাপ্ত বাইট না থাকলে কম।
জেনেরিক সমাধান # 1
উপরের রূপান্তরগুলি এখন এর জেনেরিক পদ্ধতি হিসাবে সহজেই প্রয়োগ করা যেতে পারে struct Data
:
extension Data {
init<T>(from value: T) {
self = Swift.withUnsafeBytes(of: value) { Data($0) }
}
func to<T>(type: T.Type) -> T? where T: ExpressibleByIntegerLiteral {
var value: T = 0
guard count >= MemoryLayout.size(ofValue: value) else { return nil }
_ = Swift.withUnsafeMutableBytes(of: &value, { copyBytes(to: $0)} )
return value
}
}
সীমাবদ্ধতা T: ExpressibleByIntegerLiteral
এখানে যুক্ত করা হয়েছে যাতে আমরা সহজেই মানটিকে "শূন্য" তে আরম্ভ করতে পারি - এটি আসলেই কোনও বিধিনিষেধ নয় কারণ এই পদ্ধতিটি "ট্রিভাল" (পূর্ণসংখ্যার এবং ভাসমান পয়েন্ট) প্রকারের সাথেই ব্যবহার করা যেতে পারে, নীচে দেখুন।
উদাহরণ:
let value = 42.13
let data = Data(from: value)
print(data as NSData)
if let roundtrip = data.to(type: Double.self) {
print(roundtrip)
} else {
print("not enough data")
}
একইভাবে, আপনি রূপান্তর করতে পারেন অ্যারে থেকে Data
এবং ফিরে:
extension Data {
init<T>(fromArray values: [T]) {
self = values.withUnsafeBytes { Data($0) }
}
func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
_ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
return array
}
}
উদাহরণ:
let value: [Int16] = [1, Int16.max, Int16.min]
let data = Data(fromArray: value)
print(data as NSData)
let roundtrip = data.toArray(type: Int16.self)
print(roundtrip)
জেনেরিক সমাধান # 2
উপরোক্ত পদ্ধতির একটি অসুবিধা রয়েছে: এটি আসলে কেবলমাত্র "তুচ্ছ" ধরণের সাথে পূর্ণসংখ্যার এবং ভাসমান পয়েন্টের ধরণের সাথে কাজ করে। "জটিল" ধরণের পছন্দArray
String
অন্তর্নিহিত স্টোরেজটির
এবং (গোপন) পয়েন্টারগুলি থাকে এবং কেবল স্ট্রাক্টটি অনুলিপি করেই পাস করা যায় না। এটি এমন রেফারেন্স ধরণের সাথেও কাজ করবে না যা আসল অবজেক্ট স্টোরেজের কেবল পয়েন্টার।
সুতরাং যে সমস্যাটি সমাধান করুন, একটি পারেন
এমন একটি প্রোটোকল সংজ্ঞায়িত করুন যা রূপান্তর Data
ও পিছনে রূপান্তর করার জন্য পদ্ধতিগুলি সংজ্ঞায়িত করে :
protocol DataConvertible {
init?(data: Data)
var data: Data { get }
}
প্রোটোকল এক্সটেনশনে রূপান্তরগুলি ডিফল্ট পদ্ধতি হিসাবে প্রয়োগ করুন:
extension DataConvertible where Self: ExpressibleByIntegerLiteral{
init?(data: Data) {
var value: Self = 0
guard data.count == MemoryLayout.size(ofValue: value) else { return nil }
_ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
self = value
}
var data: Data {
return withUnsafeBytes(of: self) { Data($0) }
}
}
আমি এখানে একটি অনুপযুক্ত আরম্ভকারী বেছে নিয়েছি যা পরীক্ষিত বাইটের সংখ্যাটি আকারের সাথে মেলে cks
এবং পরিশেষে সমস্ত ধরণের কনফারেন্স ঘোষণা করুন যা নিরাপদে Data
এবং ফিরে রূপান্তরিত হতে পারে :
extension Int : DataConvertible { }
extension Float : DataConvertible { }
extension Double : DataConvertible { }
এটি রূপান্তরকে আরও মার্জিত করে তোলে:
let value = 42.13
let data = value.data
print(data as NSData)
if let roundtrip = Double(data: data) {
print(roundtrip)
}
দ্বিতীয় পদ্ধতির সুবিধা হ'ল আপনি অজান্তেই অনিরাপদ রূপান্তর করতে পারবেন না। অসুবিধাটি হ'ল আপনাকে পরিষ্কারভাবে সমস্ত "নিরাপদ" প্রকারের তালিকাবদ্ধ করতে হবে।
আপনি অন্যান্য ধরণের প্রোটোকলও প্রয়োগ করতে পারেন যার জন্য একটি তুচ্ছ-রূপান্তরকরণ প্রয়োজন, যেমন:
extension String: DataConvertible {
init?(data: Data) {
self.init(data: data, encoding: .utf8)
}
var data: Data {
return Data(self.utf8)
}
}
বা রূপান্তর পদ্ধতিগুলি নিজের প্রকারে রূপান্তর পদ্ধতিগুলি যা প্রয়োজন তা করার জন্য বাস্তবায়িত করুন যাতে সিরিয়ালাইজ করুন এবং একটি মানকে ডিসরিয়ালাইজ করুন।
বাইট অর্ডার
উপরের পদ্ধতিগুলিতে কোনও বাইট অর্ডার রূপান্তর হয় না, ডেটা সর্বদা হোস্ট বাইট ক্রমে থাকে। প্ল্যাটফর্মের স্বতন্ত্র উপস্থাপনের জন্য (যেমন "বিগ এন্ডিয়ান" ওরফে "নেটওয়ার্ক" বাইট ক্রম), সম্পর্কিত পূর্ণসংখ্যার বৈশিষ্ট্যগুলি ব্যবহার করুন। প্রারম্ভিক। উদাহরণ স্বরূপ:
let value = 1000
let data = value.bigEndian.data
print(data as NSData)
if let roundtrip = Int(data: data) {
print(Int(bigEndian: roundtrip))
}
জেনেরিক রূপান্তর পদ্ধতিতে অবশ্যই এই রূপান্তরটি সাধারণত করা যায়।