I'm trying to draw an MTKMesh. To do this, I will need to set bind vertex buffers before executing the draw call. The documentation for MTKMesh.vertexBuffers is as follows:
/**
#property vertexBuffers
#abstract Array of buffers in which mesh vertex data resides.
#discussion This is filled with mesh buffer objects using the layout described by the vertexDescriptor property.
Elements in this array can be [NSNull null] if the vertexDescriptor does not specify elements for buffer for the given index
*/
open var vertexBuffers: [MTKMeshBuffer] { get }
So my understanding is that I need to iterate over this array, and bind a vertex buffer for every non-null element. I have this code so far:
for (bufferIndex, vertexBuffer) in mesh.vertexBuffers.enumerated() {
if (!(vertexBuffer is NSNull)) {
renderEncoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: bufferIndex)
}
}
However, it doesn't seem to work as I get the following warning:
Cast from 'MTKMeshBuffer' to unrelated type 'NSNull' always fails
I also tried this:
if (vertexBuffer != nil) {
renderEncoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: bufferIndex)
}
But this also doesn't seem to work work, as I get the warning:
Comparing non-optional value of type 'MTKMeshBuffer' to 'nil' always returns true
How can I iterate over the non-null elements of this array?
class MTKMeshBuffer is a subclass of NSObject. Apparently the declaration
open var vertexBuffers: [MTKMeshBuffer] { get }
is “lying” – the array elements can be pointers to MTKMeshBuffer instances or to NSNull instances. That is no problem in Objective-C because one can freely cast between different types of object pointers, and something like
for (MTKMeshBuffer *vertexBuffer in mesh.vertexBuffers) {
if (![vertexBuffer isKindOfClass:[NSNull class]]) {
//
}
}
compiles without warnings in Objective-C.
The Swift compiler does not accept this “lie” so easily: You have to cast the MTKMeshBuffer pointer to a NSObject pointer (the common superclass of MTKMeshBuffer and NSNull) before you can test for the actual type:
for (bufferIndex, vertexBuffer) in vertexBuffers.enumerated() {
if !(vertexBuffer as NSObject is NSNull) {
// ...
}
}
Alternatively one can use the Objective-C isKindOfClass method, which is imported to Swift as isKind(of:):
for (bufferIndex, vertexBuffer) in vertexBuffers.enumerated() {
if !vertexBuffer.isKind(of: NSNull.self) {
// ...
}
}
Related
I'm currently reading the excellent Advanced Swift book from objc.io, and I'm running into something that I don't understand.
If you run the following code in a playground, you will notice that when modifying a struct contained in a dictionary a copy is made by the subscript access, but then it appears that the original value in the dictionary is replaced by the copy. I don't understand why. What exactly is happening ?
Also, is there a way to avoid the copy ? According to the author of the book, there isn't, but I just want to be sure.
import Foundation
class Buffer {
let id = UUID()
var value = 0
func copy() -> Buffer {
let new = Buffer()
new.value = self.value
return new
}
}
struct COWStruct {
var buffer = Buffer()
init() { print("Creating \(buffer.id)") }
mutating func change() -> String {
if isKnownUniquelyReferenced(&buffer) {
buffer.value += 1
return "No copy \(buffer.id)"
} else {
let newBuffer = buffer.copy()
newBuffer.value += 1
buffer = newBuffer
return "Copy \(buffer.id)"
}
}
}
var array = [COWStruct()]
array[0].buffer.value
array[0].buffer.id
array[0].change()
array[0].buffer.value
array[0].buffer.id
var dict = ["key": COWStruct()]
dict["key"]?.buffer.value
dict["key"]?.buffer.id
dict["key"]?.change()
dict["key"]?.buffer.value
dict["key"]?.buffer.id
// If the above `change()` was made on a copy, why has the original value changed ?
// Did the copied & modified struct replace the original struct in the dictionary ?
dict["key"]?.change() // Copy
is semantically equivalent to:
if var value = dict["key"] {
value.change() // Copy
dict["key"] = value
}
The value is pulled out of the dictionary, unwrapped into a temporary, mutated, and then placed back into the dictionary.
Because there's now two references to the underlying buffer (one from our local temporary value, and one from the COWStruct instance in the dictionary itself) – we're forcing a copy of the underlying Buffer instance, as it's no longer uniquely referenced.
So, why doesn't
array[0].change() // No Copy
do the same thing? Surely the element should be pulled out of the array, mutated and then stuck back in, replacing the previous value?
The difference is that unlike Dictionary's subscript which comprises of a getter and setter, Array's subscript comprises of a getter and a special accessor called mutableAddressWithPinnedNativeOwner.
What this special accessor does is return a pointer to the element in the array's underlying buffer, along with an owner object to ensure that the buffer isn't deallocated from under the caller. Such an accessor is called an addressor, as it deals with addresses.
Therefore when you say:
array[0].change()
you're actually mutating the actual element in the array directly, rather than a temporary.
Such an addressor cannot be directly applied to Dictionary's subscript because it returns an Optional, and the underlying value isn't stored as an optional. So it currently has to be unwrapped with a temporary, as we cannot return a pointer to the value in storage.
In Swift 3, you can avoid copying your COWStruct's underlying Buffer by removing the value from the dictionary before mutating the temporary:
if var value = dict["key"] {
dict["key"] = nil
value.change() // No Copy
dict["key"] = value
}
As now only the temporary has a view onto the underlying Buffer instance.
And, as #dfri points out in the comments, this can be reduced down to:
if var value = dict.removeValue(forKey: "key") {
value.change() // No Copy
dict["key"] = value
}
saving on a hashing operation.
Additionally, for convenience, you may want to consider making this into an extension method:
extension Dictionary {
mutating func withValue<R>(
forKey key: Key, mutations: (inout Value) throws -> R
) rethrows -> R? {
guard var value = removeValue(forKey: key) else { return nil }
defer {
updateValue(value, forKey: key)
}
return try mutations(&value)
}
}
// ...
dict.withValue(forKey: "key") {
$0.change() // No copy
}
In Swift 4, you should be able to use the values property of Dictionary in order to perform a direct mutation of the value:
if let index = dict.index(forKey: "key") {
dict.values[index].change()
}
As the values property now returns a special Dictionary.Values mutable collection that has a subscript with an addressor (see SE-0154 for more info on this change).
However, currently (with the version of Swift 4 that ships with Xcode 9 beta 5), this still makes a copy. This is due to the fact that both the Dictionary and Dictionary.Values instances have a view onto the underlying buffer – as the values computed property is just implemented with a getter and setter that passes around a reference to the dictionary's buffer.
So when calling the addressor, a copy of the dictionary's buffer is triggered, therefore leading to two views onto COWStruct's Buffer instance, therefore triggering a copy of it upon change() being called.
I have filed a bug over this here. (Edit: This has now been fixed on master with the unofficial introduction of generalised accessors using coroutines, so will be fixed in Swift 5 – see below for more info).
In Swift 4.1, Dictionary's subscript(_:default:) now uses an addressor, so we can efficiently mutate values so long as we supply a default value to use in the mutation.
For example:
dict["key", default: COWStruct()].change() // No copy
The default: parameter uses #autoclosure such that the default value isn't evaluated if it isn't needed (such as in this case where we know there's a value for the key).
Swift 5 and beyond
With the unofficial introduction of generalised accessors in Swift 5, two new underscored accessors have been introduced, _read and _modify which use coroutines in order to yield a value back to the caller. For _modify, this can be an arbitrary mutable expression.
The use of coroutines is exciting because it means that a _modify accessor can now perform logic both before and after the mutation. This allows them to be much more efficient when it comes to copy-on-write types, as they can for example deinitialise the value in storage while yielding a temporary mutable copy of the value that's uniquely referenced to the caller (and then reinitialising the value in storage upon control returning to the callee).
The standard library has already updated many previously inefficient APIs to make use of the new _modify accessor – this includes Dictionary's subscript(_:) which can now yield a uniquely referenced value to the caller (using the deinitialisation trick I mentioned above).
The upshot of these changes means that:
dict["key"]?.change() // No copy
will be able to perform an mutation of the value without having to make a copy in Swift 5 (you can even try this out for yourself with a master snapshot).
I was taking a deep look into Apples SpriteKit & GameplayKit example code and found a Project called 'DemoBots' written in Swift. There are some very interesting concepts used in that projects which I wanted to adapt into my projects.
I was already working with encapsulating the collision-handling into a handler-class something that is very similar to the way collisions are handled in that example code.
In this project I found the following code for a struct called RPColliderType:
struct RPColliderType: OptionSetType, Hashable, CustomDebugStringConvertible {
// MARK: Static properties
/// A dictionary to specify which `ColliderType`s should be notified of contacts with other `ColliderType`s.
static var requestedContactNotifications = [RPColliderType: [RPColliderType]]()
/// A dictionary of which `ColliderType`s should collide with other `ColliderType`s.
static var definedCollisions = [RPColliderType: [RPColliderType]]()
// MARK: Properties
let rawValue: UInt32
// MARK: Options
static var Obstacle: RPColliderType { return self.init(rawValue: 1 << 0) }
static var PlayerBot: RPColliderType { return self.init(rawValue: 1 << 1) }
static var TaskBot: RPColliderType { return self.init(rawValue: 1 << 2) }
// MARK: Hashable
var hashValue: Int {
return Int(rawValue)
}
// MARK: SpriteKit Physics Convenience
/// A value that can be assigned to a 'SKPhysicsBody`'s `categoryMask` property.
var categoryMask: UInt32 {
return rawValue
}
/// A value that can be assigned to a 'SKPhysicsBody`'s `collisionMask` property.
var collisionMask: UInt32 {
// Combine all of the collision requests for this type using a bitwise or.
let mask = RPColliderType.definedCollisions[self]?.reduce(RPColliderType()) { initial, colliderType in
return initial.union(colliderType)
}
// Provide the rawValue of the resulting mask or 0 (so the object doesn't collide with anything).
return mask?.rawValue ?? 0
}
/// A value that can be assigned to a 'SKPhysicsBody`'s `contactMask` property.
var contactMask: UInt32 {
// Combine all of the contact requests for this type using a bitwise or.
let mask = RPColliderType.requestedContactNotifications[self]?.reduce(RPColliderType()) { initial, colliderType in
return initial.union(colliderType)
}
// Provide the rawValue of the resulting mask or 0 (so the object doesn't need contact callbacks).
return mask?.rawValue ?? 0
}
// MARK: ContactNotifiableType Convenience
/**
Returns `true` if the `ContactNotifiableType` associated with this `ColliderType` should be
notified of contact with the passed `ColliderType`.
*/
func notifyOnContactWithColliderType(colliderType: RPColliderType) -> Bool {
if let requestedContacts = RPColliderType.requestedContactNotifications[self] {
return requestedContacts.contains(colliderType)
}
return false
}
}
This struct is used every time you set the .collisionBitmask / .contactBitmask / .categoryBitmask property of an SKPhysicsBody like this: (I have implemented this using component & entity design guide)
class RPPhysicsComponent: GKComponent {
var physicsBody: SKPhysicsBody
init(physicsBody: SKPhysicsBody, colliderType: RPColliderType) {
self.physicsBody = physicsBody
self.physicsBody.categoryBitMask = colliderType.categoryMask
self.physicsBody.collisionBitMask = colliderType.collisionMask
self.physicsBody.contactTestBitMask = colliderType.contactMask
}
}
So far so good. Coming from Objective-C my problem is that I do not fully understand what those following lines of code out of the RPColliderType Struct do:
/// A value that can be assigned to a 'SKPhysicsBody`'s `collisionMask` property.
var collisionMask: UInt32 {
// Combine all of the collision requests for this type using a bitwise or.
let mask = RPColliderType.definedCollisions[self]?.reduce(RPColliderType()) { initial, colliderType in
return initial.union(colliderType)
}
// Provide the rawValue of the resulting mask or 0 (so the object doesn't collide with anything).
return mask?.rawValue ?? 0
}
Does that mean that every time I call that computed (that's what they are called in swift, right?) property - I do this when I assign it to a SKPhysicsBody - it adds this to those static class dictionaries. But I have a problem interpreting that 'mask' / 'reduce' / 'union' commands.
What really does that do?
collisionMask is computed property that returns a UInt32 value that can be used as a physics body's collision bit mask. It's easier to understand how this computed property works if it is broken down into its functional parts.
But first, let's add an array of the RPColliderType objects that the PlayerBot should collide with to the definedCollisions dictionary:
RPColliderType.definedCollisions[.PlayerBot] = [.Obstacle, .TaskBot]
At this point, the definedCollisions dictionary contains a single item with PlayerBot and [.Obstacle, .TaskBot] as the key and value, respectively. Think of this as the categories that can collide with a PlayerBot are Obstacle and TaskBot.
We can now use .PlayerBot to retrieve the value (i.e., the array) from the dictionary:
let array = RPColliderType.definedCollisions[.PlayerBot]
Since collisionMask is defined in the RPColliderType, self is used as the dictionary key. Also, array is an optional since a value corresponding to the key may not exist in the dictionary.
The code then combines the array of RPColliderType objects into a single RPColliderType object using the reduce method. reduce takes two arguments: an initial value (with the same type as the elements of the array) and a function (or closure) that takes a value as an argument and returns a value. In this case, the initial value is a new RPColliderType object and the closure's argument and returned value are also RPColliderType objects:
array?.reduce(RPColliderType(), aFunction)
Apple's code uses a trailing closure instead of passing a function to reduce. From the docs,
If you need to pass a closure expression to a function as the function’s final argument and the closure expression
is long, it can be useful to write it as a trailing closure instead. A trailing closure is a closure expression that is
written outside of (and after) the parentheses of the function call it supports.
reduce iterates over the array and calls the closure with the initial value and each array element as arguments and the returned value is used as the initial value for the next iteration:
let mask = array?.reduce(RPColliderType()) {
initial, colliderType in
return initial.union(colliderType)
}
where initial keeps the intermediate union of the RPColliderType array elements and colliderType is the current element of array.
At this point, mask is an RPColliderType object that we can convert to a UInt32 with
mask?.rawValue
which is the returned value of the collisionMask computed property.
I have swift class with various properties, some of which have optional types.
class UserObject: PFUser{
//optional property
var optionalPhotoURL:String? {
get {
if let optionalPhotoURL:String = objectForKey("optionalPhotoURL"){
return optionalPhotoURL
}
//not needed but just for emphasis
return nil
}
//I am unable to set UserObject.optionalPhotoURL = nil with this setters
set {
if let newPhotoURL:String = newValue! {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
}
}
I am unable to set optionalPhotoURL as nil, if it already had a previous value assigned to it.
I guess my question is, how do i "unset" an optional property with custom setter?
Update
These setters all crash
set {
if let newPhotoURL:String = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
and this
set {
if (newValue != nil) {
setObject(newValue!, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
What you have here is a computed property.
Swift properties can either be computed or stored. We can observe value changes in our stored properties by using didSet and willSet but here we still have a stored property.
In your case, since you have overridden set and get*, you don't have a stored property, you have a computed property. If you want a computed property to have a backing storage, you must create that independently.
So you may want something like this:
class FooClass {
private var storageProperty: String?
var accessProperty: String? {
get {
return self.storageProperty
}
set {
self.storageProperty = newValue
// or whatever logic you may like here
}
}
}
*: You can't override set without also overriding get. You can however override get without overriding set--this makes a readonly computed value.
Moreover, it's important that we implement our storage properties in this way over relying on key-value coding.
For starters, setObject(forKey:) approach doesn't even work on pure Swift types. This will only work on objects which inherit from Objective-C types. It's an inherited method from NSObject's compliance to NSKeyValueCoding protocol. Why the base object of Objective-C conforms to so many protocols is beyond me... but it does and there's nothing we can do about it.
If we have a code base in which some of our objects are inheriting from Objective-C objects (which basically any project will have, UIViewController, etc), and some of our objects are pure Swift objects (which you will tend to have when you're creating your own Swift classes from scratch), then our Swift objects will not be able to implement this same pattern. If we have some objects of both types, we'll either have to implement the pattern I show above for all of them (and then we have consistency) or we'll have to implement one pattern for some types and another for other types (Swift structs would definitely have to implement the above pattern, you can't just make them inherit from NSObject) (and then we have inconsistency, which we don't like).
But what's far worse about setObject(forKey:) is that the first argument of this method always will be of type AnyObject. There is no type safety to the method at all. Where things are stored via setObject(forKey:) is based purely on the key which we use. When we use setObject(forKey:), we take a pile of type-safety advantages that Swift gives us and we throw them out the window. If we don't care to leverage the advantages Swift gives us over Objective-C, why are we writing it in Swift at all?
We can't even make the stored property private when we use setObject(forKey:). Anyone who knows the key can call setObject(forKey:) and set that object to whatever they want. And that includes objects which are not strings. All we have to do to introduce a crash to this codebase is write a class extension or subclass which has a key collision on a different type other than what you've used (so maybe an NSData value for the same key). And even if it doesn't happen to be a different type, simply duplicating the same key for multiple properties is going to introduce bugs... and bugs that are hard to debug.
Never set a value of a computed property in its set scope by calling itself !
This causes an infinite loop and the app will crash.
I don't know which API setObject:forKey belongs to, but in the case of nil you are supposed to remove the object
set {
if let newPhotoURL = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
} else {
removeObjectForKey("optionalPhotoURL")
}
}
Your property optionalPhotoURL is a computed property, it does not store any values:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
You might want to create an additional property which actually stores the value. However, why do you want to set it to nil, since you are not deleting they object in case of nil.
I was watching a talk on swift optimization earlier and they were using an example of a struct with 5 variables 3 strings an array and a dictionary. They said to lower your reference count you could use a wrapper class. Can someone just make a dummy one to I might be able to understand it better.
A wrapper class would be used if you have performance issues with a struct which has many properties which are reference types.
A generic wrapper class:
class Wrapper<T> {
var value: T // or "let" instead of "var"
init(_ value: T) { self.value = value }
}
This is because if you assign it to another variable all pointers of the properties get copied and therefore all reference counts (see ARC) get incremented (and decremented at the end).
This problem mainly occurs when you are looping over large arrays of such structs where at each iteration a new variable gets created.
With a wrapper class only its reference count gets incremented and decremented once.
Example:
struct Big {
// "n" properties which have reference semantics
...
...
}
// "m" count
let hugeArray = [Big(), Big(), Big(), ...]
// m * n reference count operations (+1, -1)
for element in hugeArray {
// do something
}
// if huge array is of type [Wrapper<Big>]
// m * 1 reference count operations (+1, -1)
for element in hugeArray {
// do something
}
Side note: Such a class could improve performance. Use it with care if you write to it, assign it or pass it as parameter since it "changes" the semantics of your wrapped type and is no value type.
My class has a property that, in other languages, would be a simple Array of Strings, which would be initialized at an object's instantiation. In Swift, I have come up with the following:
class Foo {
var myArray: (String!)[]!
init(arraySize: Int, sourceOfData: SomeOtherClass){
myArray = Array<(String!)>(count: arraySize, repeatedValue:nil)
/* ... code to set the elements of the array using sourceOfData ... */
}
}
This is the only way I have been able to compile my code that allows pre-allocation of the Array's elements. However, I think all those exclamation marks make my code hard to read.
I know I can change my repeatedValue to an arbitrary non-nil string, and simplify the type to String[]!, but that would be a hack.
Also, I can do:
class Foo {
let myArray: String[] = []
init(sourceOfData: SomeOtherClass){
/*loop over sourceOfData*/{
myArray.append(/* computed String value */)
}
}
}
However, this has clearly worse performance, as the compiler cannot guess the length of my Array and allocate a contiguous block of memory for it. Normally, I would not care too much about optimizing the performance of this part of my code, but for this class it is critical.
Is there any way to have legible types without compromising performance?
You don't need to mark myArray as optional as long as you populate it in your init(). And if you can loop over sourceOfData using map something like this would work:
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray = sourceOfData.map {
return $0.computeStringValue()
}
}
}
if you really do need to use a loop, and you can at least determine how large an array you need, you can do something like this:
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray = Array<String>(count: SomeOtherClass.count, repeatedValue: "")
for i, item in enumerate(sourceOfData) {
myArray[i] = item.computeStringValue()
}
}
}
One last note about performance: LLVM is a very sophisticated compiler. You say that it is "obviously worse performance", but this is the kind of code for which static analysis may actually be able to determine the appropriate size of the array. I suggest profiling it with real data for your use case.
You can use the reserveCapacity method on Array. This will make sure there is enough pre-allocated memory to hold your data.
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray.reserveCapacity(sourceOfData.count)
// loop over data calling .append()
}
}