UnsafePointer<UInt8> initializer in Swift 3 - ios

I have a receipt validation class that is deprecated since Swift 3 has released. I fixed some issues, but I still have many ...
Here is the GitHub source code I used : https://gist.github.com/baileysh9/4386ea92b047d97c7285#file-parsing_productids-swift and https://gist.github.com/baileysh9/eddcba49d544635b3cf5
First Error :
var p = UnsafePointer<UInt8>(data.bytes)
Compiler throws : Cannot invoke initializer for type UnsafePointer(UInt8) with an argument list of type UnsafeRawPointer
Second error
while (ptr < end)
Binary operators < cannot be applied to two UnsafePointer(UInt8) operands
Thank you very much in advance :)
EDIT
Thanks to LinShiwei answer I found a solution to UnsafePointer declaration. It compiles but not tested yet (because other errors avoid me to test) :
func getProductIdFromReceipt(_ data:Data) -> String?
{
let tempData: NSMutableData = NSMutableData(length: 26)!
data.withUnsafeBytes {
tempData.replaceBytes(in: NSMakeRange(0, data.count), withBytes: $0)
}
var p: UnsafePointer? = tempData.bytes.assumingMemoryBound(to: UInt8.self)

In Swift 3, you cannot init an UnsafePointer using an UnsafeRawPointer.
You can use assumingMemoryBound(to:) to convert an UnsafeRawPointer into an UnsafePointer<T>. Like this:
var ptr = data.bytes.assumingMemoryBound(to: UInt8.self)
Use debugDescription or distance(to:) to compare two pointer.
while(ptr.debugDescription < endPtr.debugDescription)
or
while(ptr.distance(to:endPtr) > 0)

It is possible to put a regular pointer sign i C & in front of a Int8 array or Uint8 array to make a pointer to supply a C-function input. Like the &aBuffer array below (but the data array must copied locally first, to keep control of the storage of the data storage until finished with the operation, you get an error else). Here in a routine handling dropInteraction data (delivering a byte array):
func interpretInstanceData(filename: String, Buffer: [UInt8]) -> String {
var aBuffer = Buffer
let sInstanceData = String(cString: Ios_C_InterpretInstanceData(filename, &aBuffer, Int32(aBuffer.count)))
The question is slightly old. But googling for a solution on the topic of converting a swift byte array to a C-pointer (what else is UnsafePointer< UInt8 >). This question made a hit. But I think this answer is helpful for later editions of Swift (that I use). Would have worked even then. Worked in any kind of use needing a pointer from swift (just make the array of right type first).

May have recently changed to just this, without the ".bytes." part:
var p: UnsafePointer = data.assumingMemoryBound(to: UInt8.self)
from the original:
var p = UnsafePointer<UInt8>(data.bytes)

Related

Swift 3 Conversion that results in "Cannot pass immutable as inout" [duplicate]

This question already has an answer here:
Cannot pass immutable value as inout argument: function call returns immutable value
(1 answer)
Closed 6 years ago.
I'm a complete Swift newbie, but I'm writing an app for BLE using swift and have run into an issue. I'm working off of some open source code that I found in order to understand how to structure an iOS app and communicate with BLE, and when I converted it to Swift 3, a number of errors came up.
Code:
func int8Value() -> Int8 {
var value: Int8 = 0
copyBytes(to: &UInt8(value), count: MemoryLayout<Int8>.size)
return value
}
Error:
Cannot pass immutable value as inout argument: function call returns immutable value
I've been looking online for solutions to this and have found the following:
NSData to [Uint8] in Swift
CBCharacteristic value in swift3
I tried to implement these, taking a look at the following lines of code:
if let data = characteristic.value {
var bytes = Array(repeating: 0 as UInt8,count:someData.count/MemoryLayout<UInt8>.size)
data.copyBytes(to: &bytes, count:data.count)
}
and
let data = "foo".data(using: .utf8)!
let array = [UInt8](data)
let array = data.withUnsafeBytes {
[UInt8](UnsafeBufferPointer(start: $0, count: data.count))
}
I don't really understand the correlation between the them other than a few common variables. Can someone explain what is happening inside of the CopyBytes function (what "to" and "count" are doing), what the error is coming from, and if the examples I've been looking at have anything to do with the method I'm trying to fix?
It looks like there was an issue with the type casting from Int8 to UInt8, and taking the address of the resulting UInt8 conversion. The result of the cast is an immutable value, whose memory location cannot be passed as the function argument. If you simply initialize the variable as an unsigned int, it should pass the address just fine.
The following code should work:
func int8Value() -> Int8 {
var value: UInt8 = 0
copyBytes(to: &value, count: MemoryLayout<Int8>.size)
return Int8(value)
}

Converting C pointers to Swift 3

I have the code:
let data = Data(bytes: UnsafePointer<UInt8>(audioBuffer.mData), count: Int(bufferSize))
and
let u16 = UnsafePointer<Int32>(audioBuffer.mData).pointee
Both of which work in Swift 2.3 but not in Swift 3. How do I convert them so they act equivalently? (and why?)
To read 16-bit audio samples from Audio Unit callback buffers in Swift 3, I use:
let bufferPointer = UnsafeMutableRawPointer(mBuffers.mData)
if var bptr = bufferPointer {
for i in 0..<(Int(frameCount)) {
let oneSampleI16 = bptr.assumingMemoryBound(to: Int16.self).pointee
// do something with the audio sample
bptr += 1
}
}
The rest of the Audio Session and Audio Unit code is in this gist: https://gist.github.com/hotpaw2/630a466cc830e3d129b9
I can't say I understand this well, nor have I read the document, but it looks like swift3 pointer casts are scoped to avoid or limit aliasing, so you can't (easily) have two different views of the same piece of memory, or at least not for very long. This means you must either copy the cast data out or do whatever you need to do within a cast callback.
Why eliminate aliasing? I guess it makes for happier compilers.
For Data:
// [NS]Data. probably copying the data
Data(bytes: audioBuffer.mData!, count: Int(audioBuffer.mDataByteSize))
For numeric arrays:
// cast the data to Int32s & (optionally) copy the data out
let umpInt32 = audioBuffer.mData!.assumingMemoryBound(to: Int32.self)
let frameCount = Int(audioBuffer.mDataByteSize/4)
var u32 = [Int32](repeating: 0, count: frameCount)
// copy data from buffer
u32.withUnsafeMutableBufferPointer {
$0.baseAddress!.initialize(from: umpInt32, count: frameCount)
}
p.s. there's some confusion in your code. is u16 supposed to be an array of Int32s? Or UInt16s? Or something else?
Check the latest reference of Data.init(bytes:count:).
The type of the parameter bytes is UnsafeRawPointer, which accepts UnsafeMutableRawPointer. And the type of AudioBuffer.mData is UnsafeMutableRawPointer?. You have no need to convert using initializer.
let data = Data(bytes: audioBuffer.mData!, count: Int(bufferSize))
(You just need to explicitly unwrap mData, as it is imported as nullable type, UnsafeMutableRawPointer?, but you need to pass non-nil UnsafeRawPointer (or UnsafeMutableRawPointer).
The second example, you'd better check what sort of methods are available for UnsafeMutableRawPointer. You can find load(fromByteOffset:as:) method, and can use it like this.
let i32 = audioBuffer.mData!.load(as: Int32.self)
`load(

Swift String from imported unsigned char 2D array

I am using a 3rd party C library in my iOS application, which I am in the process of converting from Objective-C to Swift. I hit an obstacle when attempting to read one of the structs returned by the C library in Swift.
The struct looks similar to this:
typedef unsigned int LibUint;
typedef unsigned char LibUint8;
typedef struct RequestConfiguration_ {
LibUint8 names[30][128];
LibUint numberNames;
LibUint currentName;
} RequestConfiguration;
Which is imported into Swift as a Tuple containing 30 Tuples of 128 LibUint8 values. After a long time of trial and error using nested withUnsafePointer calls, I eventually began searching for solutions to iterating a Tuple in Swift.
What I ended up using is the following functions:
/**
* Perform iterator on every children of the type using reflection
*/
func iterateChildren<T>(reflectable: T, #noescape iterator: (String?, Any) -> Void) {
let mirror = Mirror(reflecting: reflectable)
for i in mirror.children {
iterator(i.label, i.value)
}
}
/**
* Returns a String containing the characters within the Tuple
*/
func libUint8TupleToString<T>(tuple: T) -> String {
var result = [CChar]()
let mirror = Mirror(reflecting: tuple)
for child in mirror.children {
let char = CChar(child.value as! LibUint8)
result.append(char)
// Null reached, skip the rest.
if char == 0 {
break;
}
}
// Always null terminate; faster than checking if last is null.
result.append(CChar(0))
return String.fromCString(result) ?? ""
}
/**
* Returns an array of Strings by decoding characters within the Tuple
*/
func libUint8StringsInTuple<T>(tuple: T, length: Int = 0) -> [String] {
var idx = 0
var strings = [String]()
iterateChildren(tuple) { (label, value) in
guard length > 0 && idx < length else { return }
let str = libUint8TupleToString(value)
strings.append(str)
idx++
}
return strings
}
Usage
func handleConfiguration(config: RequestConfiguration) {
// Declaration types are added for clarity
let names: [String] = libUint8StringsInTuple(config.names, config.numberNames)
let currentName: String = names[config.currentName]
}
My solution uses reflection to iterate the first Tuple, and reflection to iterate the second, because I was getting incorrect strings when using withUnsafePointer for the nested Tuples, which I assume is due to signage. Surely there must be a way to read the C strings in the array, using an UnsafePointer alike withUsafePointer(&struct.cstring) { String.fromCString(UnsafePointer($0)) }.
To be clear, I'm looking for the fastest way to read these C strings in Swift, even if that involves using Reflection.
Here is a possible solution:
func handleConfiguration(var config: RequestConfiguration) {
let numStrings = Int(config.numberNames)
let lenStrings = sizeofValue(config.names.0)
let names = (0 ..< numStrings).map { idx in
withUnsafePointer(&config.names) {
String.fromCString(UnsafePointer<CChar>($0) + idx * lenStrings) ?? ""
}
}
let currentName = names[Int(config.currentName)]
print(names, currentName)
}
It uses the fact that
LibUint8 names[30][128];
are 30*128 contiguous bytes in memory. withUnsafePointer(&config.names)
calls the closure with $0 as a pointer to the start of that
memory location, and
UnsafePointer<CChar>($0) + idx * lenStrings
is a pointer to the start of the idx-th subarray. The above code requires
that each subarray contains a NUL-terminated UTF-8 string.
The solution suggested by Martin R looks good to me and, as far as I can see from my limited testing, does work. However, as Martin pointed out, it requires that the strings be NUL-terminated UTF-8. Here are two more possible approaches. These follow the principle of handling the complexity of C data structures in C instead of dealing with it in Swift. Which of these approaches you choose depends on what specifically you are doing with RequestConfiguration in your app. If you are not comfortable programming in C, then a pure Swift approach, like the one suggested by Martin, might be a better choice.
For the purposes of this discussion, we will assume that the 3rd party C library has the following function for retrieving RequestConfiguration:
const RequestConfiguration * getConfig();
Approach 1: Make the RequestConfiguration object available to your Swift code, but extract names from it using the following C helper function:
const unsigned char * getNameFromConfig(const RequestConfiguration * rc, unsigned int nameIdx)
{
return rc->names[nameIdx];
}
Both this function's signature and the RequestConfiguration type must be available to the Swift code via the bridging header. You can then do something like this in Swift:
var cfg : UnsafePointer<RequestConfiguration> = getConfig()
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig(cfg, cfg.memory.currentName)))
{
print(s)
}
This approach is nice if you need the RequestConfiguration object available to Swift in order to check the number of names in multiple places, for example.
Approach 2: You just need to be able to get the name at a given position. In this case the RequestConfiguration type does not even need to be visible to Swift. You can write a helper C function like this:
const unsigned char * getNameFromConfig1(unsigned int idx)
{
const RequestConfiguration * p = getConfig();
return p->names[idx];
}
and use it in Swift as follows:
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig1(2)))
{
print(s)
}
This will print the name at position 2 (counting from 0). Of course, with this approach you might also want to have C helpers that return the count of names as well as the current name index.
Again, with these 2 approaches it is assumed the strings are NUL-terminated UTF-8. There are other approaches possible, these are just examples.
Also please note that the above assumes that you access RequestConfiguration as read-only. If you also want to modify it and make the changes visible to the 3rd party library C code, then it's a different ballgame.

C array memory deallocation from swift

var cpuInfo: processor_info_array_t = nil
var numCpuInfo: mach_msg_type_number_t = 0
var coresTotalUsage: Float = 0.0
var numCPUsU: natural_t = 0
let err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo);
assert(err == KERN_SUCCESS, "Failed call to host_processor_info")
Hi, I am calling the above C API host_processor_info to get process load informations from swift, no problem there.
cpuInfo is a inout parameter (pointer) that, on return, will point to a structure containing the CPU information allocated by that API.
The caller is reponsible for deallocating the memory; I can do that easily from objective C but haven't had any luck in swift. I know I could wrap that call into an objective C extension but I'm trying to learn swift and would like, if possible, avoid the obj-c solution.
in obj-c I would deallocate with:
size_t cpuInfoSize = sizeof(integer_t) * numCpuInfo;
vm_deallocate(mach_task_self(), (vm_address_t) cpuInfo, cpuInfoSize)
cpuInfo in swift is an UnsafeMutablePointer not convertible into a vm_address_t.
Any help appreciated, thanks.
processor_info_array_t is a pointer type, and vm_address_t is an integer type
(ultimately an alias for UInt). (Judging from the comments in <i386/vm_types.h>
this might to be for historical reasons.)
The only way to convert a pointer to an integer (of the same size) in Swift is unsafeBitCast.
mach_init.h defines
extern mach_port_t mach_task_self_;
#define mach_task_self() mach_task_self_
Only the extern variable is visible in Swift, not the macro.
This gives:
let cpuInfoSize = vm_size_t(sizeof(integer_t)) * vm_size_t(numCpuInfo)
vm_deallocate(mach_task_self_, unsafeBitCast(cpuInfo, vm_address_t.self), cpuInfoSize)
In Swift 4, the equivalent code appears to be:
let cpuInfoSize = vm_size_t(MemoryLayout<integer_t>.stride * Int(numCpuInfo))
vm_deallocate(mach_task_self_, vm_address_t(bitPattern: cpuInfo), cpuInfoSize)
In particular, the initializer UInt(bitPattern:) is now apparently preferred to unsafeBitCast() to initialize an unsigned integer with the bit pattern of a pointer (I guess this usage is not longer considered "unsafe"). It correctly handles a nil pointer, returning 0 in this case.

Swift: Errors when using different integer sizes

I've been trying out Swift, since it's obviously the direction that Apple wants us to go in.
However, I've been really annoyed with the fact that you can't seem to add integers of different sizes:
var a: Int64 = 1500
var b: Int32 = 12349
var c = a + b
if a < b { ... }
The yielded error is "Could not find an overload for '+' that accepts the supplied argument' — obviously since they are object types. None of the class methods seem to be of any help in up/down-converting integers.
Same situation applies with any of the type aliases, obviously, (CInt + CLong).
I can see a lot of real-world situations where it is immensely practical to be able to do integer arithmetic let alone comparisons or bitwise operations on two disparately-sized integers.
How to solve this? Explicit casting with the as operator doesn't seem to work. The Swift language book isn't much help either as it doesn't really discuss this scenario.
The Swift language book does discuss this scenario in the chapter “Numeric Type Conversion”:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values.
let a: Int64 = 1500
let b: Int32 = 12349
let c = a + Int64(b)
println("The value of c is \(c)")

Resources