'How can I find out if an SKTexture is the placeholder image

In SpriteKit, if you load an image with the [SKTexture textureWithImageNamed:] method, it will first search your bundles, then atlases, if it fails to find your texture, it will then create a placeholder image and load it.

Is there a way to find out (without visually checking) if the loaded image is a placeholder?

This doesn't seem like a very "cocoa" way to handle this type of error.

developer.apple.com is down now, so I figured I would pose this question to SO.



Solution 1:[1]

SKTexture has some private properties that would be helpful (see e.g. https://github.com/luisobo/Xcode-RuntimeHeaders/blob/master/SpriteKit/SKTexture.h), but in Swift and during development I'm using this:

extension SKTexture {
    public var isPlaceholderTexture:Bool {
        if size() != CGSize(width: 128, height: 128) {
            return false
        }

        return String(describing: self).contains("'MissingResource.png'")
    }
}

Attention!:

This only works, if you are using a SKTextureAtlas:

let t1 = SKTextureAtlas(named: "MySprites").textureNamed("NonExistingFoo")
// t1.isPlaceholderTexture == true

let t2 = SKTexture(imageNamed: "NonExistingBar")
// t2.isPlaceholderTexture == false

Solution 2:[2]

You can check if the atlas contains the image. I created the following method in my AtlasHelper:

+(BOOL) isTextureWithName:(NSString *) name existsInAtlas:(NSString *)atlasName
{
    SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:atlasName];
    return [atlas.textureNames containsObject:name];
}

Solution 3:[3]

Here is a Swift version of the answer:

guard let spriteNode = node as? SKSpriteNode,
      let nodeName = spriteNode.name
else { return }
        
let nextAtlas = SKTextureAtlas(
    named: "2ndPlayer-Skin2")

if nextAtlas.textureNames.contains(
   "\(nodeName)-Skin2.png") { // NEED FULL NAME

     let texture = nextAtlas.textureNamed(
                "\(nodeName)-Skin2")  // DONT NEED FULL

     spriteNode.texture = texture   
     spriteNode.size = texture.size()
}

Thankfully this works, of course there's always some "way" right? ;)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Gal Marom
Solution 3 rezwits