How can I use UnsafeMutablePointer<T?> as UnsafeMutablePointer<UnsafeRawPointer?>!
e.g. Trying to allocate n blocks of memory for type T, to get values from a CFSet cfsetref:
var array = UnsafeMutableRawPointer<T?>.allocate(capacity: n)
CFSetGetValues(cfsetref, array) // error
Which gives the error
Cannot convert value of type 'UnsafeMutablePointer<T?>' to expected
argument type 'UnsafeMutablePointer<UnsafeRawPointer?>!'
I tried declaring array as UnsafeMutablePointer<UnsafeRawPointer?> then doing
for i in 0..<n {
var d = array[i]
d?.bindMemory(to: T.self, capacity: 1)
}
But I still get EXC_BAD_INSTRUCTION errors when attempting to access array[i] (after binding the memory again to T)
Many things depends on how you get your cfsetref and what actually is T.
But anyway, CFSetGetValues expects UnsafeMutablePointer<UnsafeRawPointer?>! as shown in the error message.
let n = CFSetGetCount(cfsetref)
let array = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: n)
array.initialize(to: nil, count: n)
CFSetGetValues(cfsetref, array)
To safely access the contents of array, you need to know how T is managed by Swift ARC. For example, assuming T is NSNumber, you need to tell Swift ARC to manage the result with writing something like this:
let managedArray = UnsafeMutableBufferPointer(start: array, count: n).map{Unmanaged<NSNumber>.fromOpaque($0!).takeRetainedValue()}
print(managedArray)
But as well as other CF-collection types, the better way to handle CFSet is bridging it to Swift Set:
if let swiftSet = cfsetref as? Set<NSNumber> {
let swiftArray = Array(swiftSet)
print(swiftArray)
}
How do you get your cfsetref and what actually is T? With such information, I would try to tell you what sort of code you need to write in your actual case.
Related
I'm trying to implement a method to send an array of u32 (eventually an array of arrays of usize, if possible), since you can't just declare a public array field on a wasm_bindgen type. However, using the example outlined in the wasm_bindgen PR 1749, I can't seem to convert arrays or slices to a js_sys::Array; it only works for Vecs. My question is, why? See below
pub fn test() -> js_sys::Array {
let arr: [u32; 5] = [0,1,2,3,4];
let slice = &arr[0..2];
let vec: Vec<u32> = vec![0,1,2];
arr.into_iter().map(JsValue::from).collect() // This doesn't work
slice.into_iter().map(JsValue::from).collect() // Also doesn't work
vec.into_iter().map(JsValue::from).collect() // Works as expected!
}
The specific error is: the trait 'wasm_bindgen::cast::JsCast' is not implemented for 'u32'
The array and slice examples don't seem to work for any number type, ints or floats. My only thought is because the implementation in PR 1749 seems to expect a ref, and arrays are allocated on the stack that the FromIterator is not valid for items in an array?
Is there some other way to achieve what I'm trying to do with the array (passing across the boundary to JS through wasm_bindgen), or if not, why? I'd be very interested to know.
Although Rust arrays and slices have an into_iter method it returns the same Iterator as the iter method does which iterates over references to values instead of the values themselves. Yes, this is confusing. Since JsValue::from is implemented for u32 but not for &u32 you can take your Iterator<Item = &u32> and convert it to a Iterator<Item = u32> using the copied method. Fixed working examples:
use wasm_bindgen::JsValue;
use js_sys::Array;
fn array_to_js_array(array: [u32; 5]) -> Array {
array.iter().copied().map(JsValue::from).collect()
}
fn slice_to_js_array(slice: &[u32]) -> Array {
slice.iter().copied().map(JsValue::from).collect()
}
fn vec_to_js_array(vec: Vec<u32>) -> Array {
vec.into_iter().map(JsValue::from).collect()
}
I have an array of object, each object contains a discount rate , I need to sort them increasingly by their rate,
struct ShopDetails {
var shopId: Int?
var discountRate: String?
init(with json: Dictionary<String,Any>) {
shopId = json["id"] as? Int
discountRate = json["discount"] as? String
}
I tired to sort them using this method;
func getShopsByDiscount() {
let sortedImages = self.copyOfShops.sorted(by: { (shop1: ShopDetails, shop2: ShopDetails) -> Bool in
return Int(shop1.discountRate) < Int(shop2.discountRate)
})
}
I tried to cast the rate to integer, since its been received form the backend as string, but I got an error:
value of type Any has no member discountRate.
any idea how to do it? if there is a way to do it without casting it will be better
First, you need to verify that the array you're starting with is of type [ShopDetails]. The error indicates that this is probably an Objective-C NSArray, which won't work as well in Swift. If you're unclear about this, I suggest you Google the topic: there's no reason to use NSArray in Swift.
Below, I assume the array is the correct type ([ShopDetails]). From here, you need to do two additional things, because discountRate is of type String?.
You need to check if the string is actually there
You need to check if it can actually be expressed as an Int.
With these things in mind, your sort function can look like this:
let sortedImages = copyOfShops.sorted(by: {
(shop1: ShopDetails, shop2: ShopDetails) -> Bool in
if let shop1String = shop1.discountRate, let shop1Value = Int(shop1String),
let shop2String = shop2.discountRate, let shop2Value = Int(shop2String) {
return shop1Value < shop2Value
}
return true
})
That being said, the best way to handle this is to change the type of discountRate from String? to Int, and do the above checks when you init(with json: Dictionary<String,Any>). If the server giving you the dictionary is something you control, have it switch to passing back Ints instead of Strings, and stop dealing with optionals if you don't have to.
I'm pretty new to Swift, and I'm trying to store my data as a 2D AnyObject array. I have declared var internalData = [[AnyObject]]() and a struct like so:
struct WiFiData {
var latency: Double
var duration: Double
}
Now, in another function, I would like to switch on the instance variable currentExit, which is an enum:
private var currentExit = Exit.A
enum Exit {
case A
case B
case C
case NotSelected
}
func someFunc() {
switch self.currentExit {
case .A:
self.internalData[0].append(WiFiData(latency: 1.5, duration: 4.0) as AnyObject) // <- CRASHES ON THIS LINE
......// other cases
}
However, it always crashes on the line self.internalData[0].append(WiFiData(latency: 1.5, duration: 4.0) as AnyObject) with the following error:
fatal error: Index out of range
Can anyone tell me why and how I could fix it? Any help is appreciated, thanks!
You instantiated a 2d array with [[AnyObject]](), but it's still empty, meaning there's nothing at self.internalData[0] for you to append to. There are a lot of things you could do to handle this, but if you know you're going to have 3 arrays inside self.internalData you may as well instantiate each internal array like so:
self.internalData = [[AnyObject](), [AnyObject](), [AnyObject]()]
Now you do have an empty array at self.internalData[0] that you can append items to.
It seems, though, like if you already know you're going to have 3 arrays of WiFiData it'd be even better just to create 3 variables:
var a = [WiFiData]()
var b = [WiFiData]()
etc.
and then you can access the individual arrays by name.
There are no "2D arrays" in Swift. There are arrays of arrays, which are different. For example, there is no promise that each row will have the same number of columns in an array of arrays.
In your case, the problem is that internalData has no elements in it. There has to be an internalData[0] element already created before you can append to it. You're assignment of var internalData = [[AnyObject]]() means there's no element 0. It's an empty array (of arrays).
Also keep in mind that the type [[AnyObject]] is very likely to cause a lot of problems for you. AnyObject is useful for working with Cocoa APIs, but generally creates a lot of headaches and should very rarely be part of a Swift property. You should almost certainly create some more specific type to hold your data. It's unclear from your example what you expect internalData to hold. Your code suggests, though, that you mean something more like:
var internalData: [Exit: [ExitRecord]] = [:]
enum Exit {
case A
case B
case C
case NotSelected
}
enum ExitRecord {
case wifi(latency: Float, duration: Float)
}
func someFunc() {
switch self.currentExit {
case .A:
var currentRecords = internalData[.A] ?? []
currentRecords.append(.wifi(latency: 1.5, duration: 4.0))
internalData[.A] = currentRecords
......// other cases
}
import Foundation
func insertionSort<T where T: Comparable>(var items:[T])-> [T] {
for (index, _) in items.enumerate().dropFirst() {
var j = index
while ((j > 0) && (items[j] < items[j-1])) {
swap(&items[j], &items[j-1])
j = j-1
}
}
return items
}
// Test the function
insertionSort([]) // Generic type array is not taking empty array
When I am trying to call insertionSort with empty array, I get
Cannot invoke 'insertionSort' with an argument list of type '([_])'
I am not able to figure out how to fix this.
To call generic functions in Swift, Swift needs to be able to infer the generic parameters.
One way giving the type information to Swift, is using an intermediate variable.
(Like noted in Lu_'s comment.)
let arr: [Int] = []
let result = insertionSort(arr)
Another way is using as.
let result = insertionSort([] as [Int])
(Remember, var parameter does not modify the actual argument. It just makes a mutable copy, but does not write it back to the original argument. Swift 3 removed var parameters, as it's so confusing. You may need to assign the return value of the function to a variable.)
I'm officially confused why this is not working (there isn't much to explain here):
protocol A {
var value: Int { get set }
}
struct B: A {
var value: Int
}
let array: [B] = [B(value: 10)]
let singleAValue: A = array[0] // extracting works as expected
var protocolArray: [A] = []
protocolArray.append(singleAValue) // we can put the value inside the `protocolArray` without problems
print(protocolArray)
let newProtocolArray: [A] = array // but why does this conversion not work?
The array of the protocol type has a different memory representation than an array of B structs. Because an array of A can contain many different types of objects, the compiler has to create an indirection (a wrapper around the elements in the array) to ensure that they all have the same size.
Since this conversion is potentially costly (if the source array is large), the compiler forces you to make it explicit by mapping over the source array. You can write either this:
let newProtocolArray = array.map { $0 as A }
or this:
let newProtocolArray: [A] = array.map { $0 }
Both are equivalent.