Swift: cannot convert value of type 'Self' to expected argument type 'UnsafePointer<Void>' - swift

I do a bunch of work with [Uint8] arrays. But I often have to recast these as NSData objects to interface with iOS frameworks such as CoreBluetooth. So I have lots of code that might look something like:
var input:[UInt8] = [0x60, 0x0D, 0xF0, 0x0D]
let data = NSData(bytes: input, length: input.count)
Being tired of having to insert this extra let data = ... line, I thought I would just extend those arrays with a computed property to do the work. Then I could just do things like:
aBluetoothPeriperal.write(myBytes.nsdata, ...)
So it's basically just extension sugar. I can't extend Array, but I can extend a protocol:
extension SequenceType where Generator.Element == UInt8 {
var nsdata:NSData {
return NSData(bytes: self, length: self.count)
}
}
Which produces an error that looks like:
Playground execution failed: MyPlayground.playground:3:24: error: cannot convert value of type 'Self' to expected argument type 'UnsafePointer<Void>' (aka 'UnsafePointer<()>')
return NSData(bytes: self, length: self.count)
^~~~
Sadly, the more I use Swift--and I really do like some things about Swift--the more I'm reminded of my negative experiences with trying to understand reams of unhelpful compiler output when I tried my hand at C++ with lots of generics and stuff years ago. So please Obi Wan, help me see the light here!

NSData(bytes:, length:) takes an UnsafePointer<Void> as first parameter, and you cannot pass an arbitrary SequenceType here.
You can pass an Array which would be passed as the address of the
first array element. It is however not guaranteed that Array elements
are stored in contiguous memory.
Therefore:
Define an Array extension instead of a Sequence extension.
Use the withUnsafeBufferPointer() method to get a pointer
to contiguous array storage.
Possible solution:
extension Array where Element : IntegerType {
var nsdata : NSData {
return self.withUnsafeBufferPointer {
NSData(bytes: $0.baseAddress, length: self.count * strideof(Element))
}
}
}
let input:[UInt8] = [0x60, 0x0D, 0xF0, 0x0D]
print(input.nsdata) // <600df00d>
Swift does currently not allow to restrict an array extension
to a concrete type:
extension Array where Element == UInt8 { }
// error: same-type requirement makes generic parameter 'Element' non-generic
therefore it is generalized to any elements conforming to IntegerType.
For a sequence you could then do a conversion to an array first:
let data = Array(myUInt8sequence).nsdata

This seems to do what you want.
protocol ByteOnly: IntegerType {}
extension UInt8: ByteOnly {}
extension Array where Element: ByteOnly {
var n : NSData { return NSData(bytes: self, length: self.count) }
}
// does it work with UInt8
var input5:[UInt8] = [0x61, 0x0D, 0xF1, 0x0D]
let data5 = input5.n // YES
// does it work on ints?
var ints: [Int] = [3,4,5,6,7,8]
let idata5 = ints.n // no

Related

Forcing an Encoder's UnkeyedEncodingContainer to only contain one type of value

As part of a custom Encoder, I am coding an UnkeyedEncodingContainer. However, the specific format I am making it for asks that all elements of an array be of the same type. Specifically, arrays can contain :
Integers one same size
Floats or Doubles
Other arrays (not necessarily all containing the same kinds of elements)
Objects
Here is the type of answer I need : The basis of an UnkeyedEncodingContainer implementation that conforms to the protocol, and enforces that all elements be of one same type among the above specified ones.
As requested, here are examples of things that should or should not be encodable :
var valid1 = []
var valid2 = [3, 3, 5, 9]
var valid3 = ["string", "array"]
var invalid1 = [3, "test"]
var invalid2 = [5, []]
var invalid3 = [[3, 5], {"hello" : 3}]
// These may not all even be valid Swift arrays, they are only
// intended as examples
As an example, here is the best I have come up with, which does not work :
The UnkeyedEncodingContainer contains a function, checkCanEncode, and an instance variable, ElementType :
var elementType : ElementType {
if self.count == 0 {
return .None
} else {
return self.storage[0].containedType
}
}
func checkCanEncode(_ value : Any?, compatibleElementTypes : [ElementType]) throws {
guard compatibleElementTypes.contains(self.elementType) || self.elementType == .None else {
let context = EncodingError.Context(
codingPath: self.nestedCodingPath,
debugDescription: "Cannot encode value to an array of \(self.elementType)s"
)
throw EncodingError.invalidValue(value as Any, context)
}
}
// I know the .None is weird and could be replaced by an optional,
// but it is useful as its rawValue is 0. The Encoder has to encode
// the rawValue of the ElementType at some point, so using an optional
// would actually be more complicated
Everything is then encoded as a contained singleValueContainer :
func encode<T>(_ value: T) throws where T : Encodable {
let container = self.nestedSingleValueContainer()
try container.encode(value)
try checkCanEncode(value, compatibleElementTypes: [container.containedType])
}
// containedType is an instance variable of SingleValueContainer that is set
// when a value is encoded into it
But this causes an issue when it comes to nestedContainer and nestedUnkeyedContainer : (used for stored dictionaries and arrays respectively)
// This violates the protocol, this function should not be able to throw
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) throws -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
let container = KeyedContainer<NestedKey>(
codingPath: self.nestedCodingPath,
userInfo: self.userInfo
)
try checkCanEncode(container, compatibleElementTypes: [.Dictionary])
self.storage.append(container)
return KeyedEncodingContainer(container)
}
As you can see, since I need checkCanEncode to know whether it is even possible to create a NestedContainer in the first place (because if the array already has stuff inside that aren't dictionaries, then adding dictionaries to it is invalid), I have to make the function throw. But this breaks the UnkeyedEncodingContainer protocol which demands non-throwing versions.
But I can't just handle the error inside the function ! If something tries to put an array inside an array of integers, it must fail. Therefore this is an invalid solution.
Additional remarks :
Checking after having encoded the values already feels sketchy, but checking only when producing the final encoded payload is definitely a violation of the "No Zombies" principle (fail as soon as the program enters an invalid state) which I would rather avoid. However if no better solution is possible I may accept it as a last resort.
One other solution I have thought about is encoding the array as a dictionary with numbered keys, since dictionaries in this format may contain mixed types. However this is likely to pose decoding issues, so once again, it is a last resort.
You will be advised not to edit other people’s questions. If you have edits to suggest please do so in the comments, otherwise mind your own business
Unless anyone has a better idea, here is the best I could come up with :
Do not enforce that all elements be of the same type inside the UnkeyedEncodingContainer
If all elements are the same type, encode it as an array
If elements have varying types, encode it as a dictionary with integers as keys
This is completely fine as far as the encoding format goes, has minimal costs and only slightly complicates decoding (check whether keys contain integers) and greatly widens how many different Swift object will be compatible with the format.
Note : Remember that the "real" encoding step where the data is generated is not actually part of the protocol. That is where I am proposing the shenanigans should take place 😈
I don't know whether this helps you but in Swift you can overload functions. This means that you can declare functions with the same signature but with different parameter types or constraints. The compiler will take always the right choice. It's much more efficient than a type check at runtime.
The first method is called if the array conforms to Encodable
func encode<T: Encodable>(object: [T]) throws -> Data {
return try JSONEncoder().encode(object)
}
Otherwise the second method is called. If the array cannot even be encoded with JSONSerialization you can add custom encoding logic.
func encode<T>(object: [T]) throws -> Data {
do {
return try JSONSerialization.data(withJSONObject: object)
} catch {
// do custom encoding and return Data
return try myCustomEncoding(object)
}
}
This example
let array = [["1":1, "2":2]]
try encode(object: array)
calls the first method.
On the other hand this – even if the actual type is not heterogenous – calls the second method
let array : [[String:Any]] = [["1":1, "2":2]]
try encode(object: array)

"Type of expression is ambiguous without more context" when creating UInt16 array from Bluetooth characteristic

I am using Xcode 9.2 and I don't understand the reason behind the error
Type of expression is ambiguous without more context
I am getting some input when trying to create and wordArray as showed below. If I define it as UInt8 array it does work but not if I do as Uint16 since I get the error.
The original data, Characteristic.value comes from a BLE characteristic
let characteristicData = Characteristic.value
let byteArray = [UInt8](characteristicData!)
print("\(Characteristic.uuid) value as byte is->",byteArray)
let wordArray = [UInt16](characteristicData!)//Type of expression is ambiguous without more context
print("\(Characteristic.uuid) value as word is->",wordArray)
Why does this happen and how I can fix it?
characteristicData has the type Data and that conforms to the
(RandomAccess)Collection protocol with UInt8 as element type, that's why you can
initialize an [UInt8] array from it:
let byteArray = [UInt8](characteristicData)
You could equivalently write
let byteArray = Array(characteristicData)
To interpret the data as an array of a different type, use
the generic
func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType
method:
let wordArray = characteristicData.withUnsafeBytes {
[UInt16](UnsafeBufferPointer(start: $0, count: characteristicData.count/2))
}
Here the ContentType is inferred automatically as UInt16.

In Swift, what are the semantics of subscripts yielding (or receiving) non-object types?

The Swift book does not clearly document the semantics of non-object types in conjunction with subscripts. The most obvious example is a Dictionary whose value type is an Array: Array is a struct. Therefore, when a subscript returns it, we should expect it to be copied. This, however, is very inconvenient. Fortunately, it seems also not to be the case—at least not in Xcode 8.2.1 (Swift 3.1?).
Consider these examples:
var a: [Int] = [0] // [0]
var b = a // [0]
b.append(1)
b // [0, 1]
a // [0]
As we expect, the array a is copied when it is assigned to b. In contrast,
var h: [Int: [Int]] = [0: [0]] // [0: [0]]
h[0]!.append(1)
h[0] // [0, 1]
If the subscript were simply returning the value using ordinary semantics, we would expect that h[0] would still equal [0] after h[0]!.append(1), but in fact it is the array in the dictionary that is appended to. We can even see if we like that the value remains at the same location in memory, suggesting that it is semantically the same array that was appended to. (Being at the same location does not imply that, but it is not in conflict with that, either.)
var h: [Int: [Int]] = [0: [0]] // [0: [0]]
var aptr: UnsafePointer<[Int]>? = nil
withUnsafePointer(to: &h[0]!) { aptr = $0 }
aptr // UnsafePointer(0x7FFF5351C2C0)
h[0]!.append(1)
withUnsafePointer(to: &h[0]!) { aptr = $0 }
aptr // UnsafePointer(0x7FFF5351C2C0)
This fortunate but seemingly-undocumented behavior does not apply only to Arrays as Dictionary values.
struct S: CustomStringConvertible {
var i: Int = 0
var description: String { return "S(i=\(self.i))" }
}
var g: [Int: S] = [0: S()]
g[0]! // S(i=0)
g[0]!.i = 5
g[0]! // S(i=5)
And, in fact, it does not even apply only to the subscripts of Dictionary types.
struct T {
var s: S? = S()
subscript(x: Int) -> S? {
get {
return self.s
}
set(s) {
self.s = s
}
}
}
var t = T()
t[0]! // S(i=0)
var tptr: UnsafePointer<T>? = nil
withUnsafePointer(to: &t) { tptr = $0 }
tptr // UnsafePointer(0x1007F6DB8)
t[0]!.i = 5
t[0]! // S(i=5)
withUnsafePointer(to: &t) { tptr = $0 }
tptr // UnsafePointer(0x1007F6DB8)
Notably, this does somehow involve the setter: If the set under subscript is removed from the definition of T, the statement t[0]!.i = 5 produces the error
error: cannot assign to property: subscript is get-only
My preferred answer would be a pointer to some Swift documentation that clearly explains the semantics of modifications to non-object values obtained through subscripts. It appears that the language behaves as I would like it to, but I'm not comfortable relying on this behavior while it seems inconsistent with the documentation.
Array is implemented using copy-on-write, so it is not in fact copied each time it is assigned but only when it needs to be as determined by its internal state. It seems this behaviour is implemented in such a way that it is not triggered after being returned from a subscript.
update
Array subscripts are implemented using addressors, essentially the subscript accesses the array element directly. You can read some details in this document: https://github.com/apple/swift/blob/master/docs/proposals/Accessors.rst
Particularly note the section Mixed addressors, quote: 'Mixed addressors have now been adopted by Array to great success', perhaps dictionaries are using the same system now.
Also see this tweet: https://mobile.twitter.com/slava_pestov/status/778488750514970624
by someone who apparently works on the swift compiler at Apple, the related thread has some interesting links.
But essentially the answer to your question is that this isn't documented in a user friendly way, it is using special optimisations behind the scenes to make sure it works efficiently. I agree that a detailed explanation in the documentation would be helpful!
If you are concerned at using undocumented behaviour in your code a workaround would be to wrap your value type in a class before storing it in an array or dictionary. But it seems unlikely that the Swift team will make a change that breaks existing code in this way.

Subscript range of [UInt8] - Swift

So the issue I'm having is that I have an object with a argument in the init() that requires an [UInt8]. I want to be able to grab a range from another array and use that in the init. See example.
class Test {
init(fromArray: [UInt8]) {
// performs work
}
}
let myStockArray: [UInt8] = [1,2,3,4,5,6,7,8] // reference array
let test = Test(fromArray: myStockArray[1...4]) // doesn't work
How can I get this to work? The error I get is: Cannot subscript a value of type '[UInt8]' with an index of type 'CountableClosedRange'
Subscripting an array with a range doesn't return an array and this is the main issue. You are trying to setArraySlice<UInt8> type data to the constructor that have inside [UInt8] type.
Try this approach:
class Test {
init(fromArray: [UInt8]) {
// performs work
}
}
let myStockArray: [UInt8] = [1,2,3,4,5,6,7,8] // reference array
let test = Test(fromArray: Array(myStockArray[1...4]))

Creating an UnsafeMutablePointer<UnsafeMutablePointer<Float>> parameter in Swift 3

The Swift signature of the Accelerate framework vDSP_biquadm() function includes parameter types of UnsafeMutablePointer<UnsafePointer<Float>> and UnsafeMutablePointer<UnsafeMutablePointer<Float>>.
How does one declare and create such types in Swift 3, and then fill these pointer arrays with references to several Swift arrays of type [Float].
When you need to pass multiple values for UnsafeMutablePointer<T> parameters, you need to declare a variable of type [T] (aka Array<T>) and pass it as an inout argument. In your case T is UnsafeMutablePointer<Float>.
So, if you want to start with [Float], you may need to write something like this:
let input: [Float] = [/*...*/]
var output: [Float] = Array(repeating: 0, count: outputTotalSize)
input.withUnsafeBufferPointer {inBuf in
let inputPtr = inBuf.baseAddress!
output.withUnsafeMutableBufferPointer {outBuf in
let outputPtr = outBuf.baseAddress!
var pInputs: [UnsafePointer<Float>] = [inputPtr,/*...*/]
var pOutputs: [UnsafeMutablePointer<Float>] = [outputPtr/*...*/]
vDSP_biquadm(setup, &pInputs, inStride, &pOutputs, outStride, length)
}
}