Swift MetalKit unknknown return type MTKMesh.newMeshes - swift

Up until now I have been following a tutorial (released around the time of Metal 1), to learn Metal. I haven't encountered any errors I couldn't figure out until this point. I am trying to execute this code
var meshes: [AnyObject]?
//code
let device = MTLDevice() //device is fine
let asset = MDLAsset() //asset works fine
do{
meshes = try MTKMesh.newMeshes(asset: asset, device: device)
} catch //...
The error i'm getting is Cannot assign value of type '(modellOMeshes: [MDLMesh], metalKitMeshes: [MTKMesh])' to type '[AnyObject]?'
What is type of MTKMesh.newMeshes, and how can I store it in a variable? I tried casting it as! [AnyObject], but then xcode tells me that this cast would fail every time.

The return type of that method is ([MDLMesh], [MTKMesh]), a tuple comprised of an array of MTLMeshes and an array of MTKMeshes. The reason for this is that you might want the original collection of MDLMesh objects contained in the asset, in addition to the MTKMesh objects that are created for you.
So, you can declare meshes like this:
var meshes: ([MDLMesh], [MTKMesh])
Or, if you don't care about the original MDLMeshes, you can "destructure" the tuple to get just the portion you care about into a variable of type [MTKMesh]:
var meshes: [MTKMesh]
(_, meshes) = try MTKMesh.newMeshes(asset: asset, device: device)

As the function signature and the compiler error clearly show, the return type is (modelIOMeshes: [MDLMesh], metalKitMeshes: [MTKMesh]), so you should declare meshas accordingly:
var meshes: (modelIOMeshes: [MDLMesh], metalKitMeshes: [MTKMesh])?
The type is a named tuple containing two Arrays, holding MDLMesh and MTKMesh instances respectively.

Related

List all window names in Swift

Iā€™m learning Swift. How do I fix the following code to list the window names?
import CoreGraphics
let windows = CGWindowListCopyWindowInfo(CGWindowListOption.optionAll, kCGNullWindowID)
for i in 0..<CFArrayGetCount(windows) {
if let window = CFArrayGetValueAtIndex(windows, i) {
print(CFDictionaryGetValue(window, kCGWindowName))
}
}
The error:
main.swift:6:32: error: cannot convert value of type 'UnsafeRawPointer' to expected argument type 'CFDictionary?'
print(CFDictionaryGetValue(window, kCGWindowName))
^~~~~~
as! CFDictionary
It becomes easier if you avoid using the Core Foundation types and methods, and bridge the values to native Swift types as early as possible.
Here, CGWindowListCopyWindowInfo() returns an optional CFArray of CFDictionaries, and that can be bridged to the corresponding Swift type [[String : Any]]. Then you can access its values with the usual Swift methods (array enumeration and dictionary subscripting):
if let windowInfo = CGWindowListCopyWindowInfo(.optionAll, kCGNullWindowID) as? [[ String : Any]] {
for windowDict in windowInfo {
if let windowName = windowDict[kCGWindowName as String] as? String {
print(windowName)
}
}
}
You can use unsafeBitCast(_:to:) to convert the opaque raw pointer to a CFDictionary. Note that you'll also need to convert the second parameter, to a raw pointer:
CFDictionaryGetValue(unsafeBitCast(window, to: CFDictionary.self), unsafeBitCast(kCGWindowName, to: UnsafeRawPointer.self))
unsafeBitCast(_:to:) tells the compiler to treat that variable as another type, however it's not very safe (thus the unsafe prefix), recommending to read the documentation for more details, especially the following note:
Warning
Calling this function breaks the guarantees of the Swift type system; use with extreme care.
In your particular case there should not be any problems using the function, since you're working with the appropriate types, as declared in the documentation of the Foundation functions you're calling.
Complete, workable code could look something like this:
import CoreGraphics
let windows = CGWindowListCopyWindowInfo(CGWindowListOption.optionAll, kCGNullWindowID)
for i in 0..<CFArrayGetCount(windows) {
let windowDict = unsafeBitCast(CFArrayGetValueAtIndex(windows, i), to: CFDictionary.self)
let rawWindowNameKey = unsafeBitCast(kCGWindowName, to: UnsafeRawPointer.self)
let rawWindowName = CFDictionaryGetValue(windowDict, rawWindowNameKey)
let windowName = unsafeBitCast(rawWindowName, to: CFString?.self) as String?
print(windowName ?? "")
}
Update
You can bring the CoreFoundation array sooner to the Swift world by casting right from the start:
let windows = CGWindowListCopyWindowInfo(CGWindowListOption.optionAll, kCGNullWindowID) as? [[AnyHashable: Any]]
windows?.forEach { window in
print(window[kCGWindowName])
}
The code is much readable, however it might pose performance problems, as the cast to [[AnyHashable: Any]]` can be expensive for large array consisting of large dictionaries.

Convert an array of dictionaries into a set Swift 4

I have an array of dictionaries ([[Double:Double]]) which I want to convert into a Set of dictionaries. My goal is to use the .symmetricDifference to find the differences between two arrays (both are of type [[Double:Double]]). How can I do this?
I found this on hackingwithswift.com and tried to use it but I am getting this error:
Type '[[Double : Double]]' does not conform to protocol 'Hashable'
I have also tried this code...
let array1:[[Double:Double]] = [[4.5:3.678], [6.7:9.2867], [7.3: 8.7564]]
let array2:[[Double:Double]] = [[4.5:3.678], [6.7:9.2867]]
let array3 = Set<[[Double:Double]]>(array1).symmetricDifference(Set(array2)) //On this line I get the error above.
You don't want a Set of [[Double:Double]]. You want a Set of [Double:Double], because those are the objects in the array and you want them to be the objects in the Set.
Thus the right thing will happen if you simply say
let array1:[[Double:Double]] = [[4.5:3.678], [6.7:9.2867], [7.3: 8.7564]]
let set1 = Set(array1)
and so on.
This might require you to update to a newer version of Swift. It works in Swift 4.2.

Variable used within its own initial value Swift 3

I try to convert my code to swift 3 an I have spent hours on the following error:
Type 'Any' has no subscript members
Here's was my original code:
let data: AnyObject = user.object(forKey: "profilePicture")![0]
I looked at the answers here but I'm still stuck. (I do programming as a hobby, I'm not a pro :/)
I've try that:
let object = object.object(forKey: "profilePicture") as? NSDictionary
let data: AnyObject = object![0] as AnyObject
But now I get this error:
Variable used within its own initial value
Second issue: Use always a different variable name as the method name, basically use more descriptive names than object anyway.
First issue: Tell the compiler the type of the value for profilePicture, apparently an array.
if let profilePictures = user["profilePicture"] as? [[String:Any]], !profilePictures.isEmpty {
let data = profilePictures[0]
}
However, the array might contain Data objects, if so use
if let profilePictures = user["profilePicture"] as? [Data], !profilePictures.isEmpty {
let data = profilePictures[0]
}
Or ā€“ what the key implies ā€“ the value for profilePicture is a single object, who knows (but you ...)
And finally, as always, don't use NSArray / NSDictionary in Swift.

Ambiguous use of a subscript when accessing a 2-dimensional array bridged from Obj-C

This code which ran perfectly in Xcode 7.0 now complains with a error : Ambiguous use of a subscript in Xcode 7.3.1 on the second line.
let ar = sender.draggingPasteboard().propertyListForType("ABLinkedPeopleUIDsPboardType") as! NSArray?
let uniqueID = ar![0][0] as! String
I understand that the NSArray on its own is now considered bad practice, but what do I need to do to get this to compile and run?
NSArray is a single-dimensioned array, but you're trying to use it as a two-dimensional array. I can't see how this would ever compile.
You need to translate into Swift types immediately so you can continue programming in Swift, not go adrift in a sea of force-unwrapped Optionals.
How about:
if let ar = sender.draggingPasteboard().propertyListForType("ABLinkedPeopleUIDsPboardType") as? [[String]] {
// I'm assuming you're expecting to get back a two-dimensional array of Strings, or in the Obj-C realm, an NSArray of NSArrays of NSStrings
let uniqueID = ar[0][0]
}
else {
print("Property List for ABLinkedetc. is not a 2D String Array!")
}
Hayden's link is the correct general discussion but if you're new to bridging Obj C to Swift it may be difficult to apply in your particular case.

Swift Error: Ambiguous reference to member 'subscript'

I'm new to coding and picked up some open source project to get the idea.
I'm getting the error:
Ambiguous reference to member 'subscript'
in the code below:
let pictures = ( selectedRestaurant["Pictures"] as! NSArray ) // Error
let picture = ( pictures[zoomedPhotoIndex] as! NSDictionary )
let pictureURL = picture["url"] as! String
let imageURL = NSURL(string: pictureURL)
let urlRequest = NSURLRequest(URL: imageURL!)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue()) {
response, data, error in
if error == nil && data != nil {
self.imageView.image = UIImage(data: data!)
self.imageView.contentMode = UIViewContentMode.ScaleAspectFit
}
}
Just specify explicitly what is the type of pictures:
So instead of:
let pictures = selectedRestaurant["Pictures"] as! NSArray
Write:
let pictures: NSArray = selectedRestaurant["Pictures"] as! NSArray
For me the answer was to specifically state the type of array I was casting to:
if let foo = dictionary["bar"] as? [String]
It means that "Pictures" is not a valid subscript. It looks like you are creating a constant named pictures and you are trying to assign it a value of selectedRestaraunt["Pictures"] and then trying to cast it as an NSArray. If selectedrestaraunt is already an array, then what goes in the [] brackets after selectedRestaraunt should be an integer value which will refer to an index in the selectedRestaraunt array. Obviosuly "Pictures" is not an integer, it is a string.
If you are trying to access an array within an array. Meaning that Pictures is an array stored within the selectedRestarauntarray then you can access it by using selectedRestaraunt[index of Pictures array] where [index of pictures array] is an integer which is equal to the index number in which the Picutres array resides within the selectedRestaraunt array
I managed to get this error in a somewhat weird way. I had code like this:
cell.textLabel = anArrayOfStrings[indexPath.item].uppercased()
And I was stumped as to why it couldn't figure out that this was an array, even though I very clearly declared its type. I broke the line in two and finally got a helpful error message:
let name = anArrayOfStrings[indexPath.item].uppercased()
cell.textLabel = name
I was trying to assign a String to a UILabel, but somehow the point at which the type inference engine failed was at the subscript.
So my advice to anyone stumped by this is to try to break up your statement into bite-sized chunks that the Swift type inference engine can more easily digest.
As Eric and Eugene mentioned in their comments it is impossible to review the issue you are having without knowing the selectedRestaurant type. That is after all why you are getting the compiler ambiguity error.
I have to respectfully disagree with MikeG though. The problem is not one of a valid subscript. You'd be getting that kind of error, if for example you had a selectedRestaurant type of [NSNumber:AnyObject], where clearly String is no longer valid since the dictionary key could only be an NSNumber.