5

拡張するヘルパーメソッドがありますSKPhysicsContact

extension SKPhysicsContact {

    /// - returns: `[SKPhysicsBody]` containing all the bodies that match `mask`
    func bodiesMatchingCategory(mask: UInt32) -> [SKPhysicsBody] {
        let bodies = [bodyA, bodyB]
        return bodies.filter { ($0.categoryBitMask & mask) != 0 }
    }
}

渡されdidBeginContact()た でこのメソッドを呼び出しますcontact

func didBeginContact(contact: SKPhysicsContact) {
    let ballMask: UInt32 = 0x1 << 2
    let ball = contact.bodiesMatchingCategory(ballMask)
...

アプリをクラッシュさせる次のエラー メッセージが表示されることがあります (5 分の 1 など)。

-[PKPhysicsContact bodiesMatchingCategory:]: unrecognized selector sent to instance 0x165f2350

調べたところPKPhysicsContact、プライベート フレームワークの一部です (リンク)。 SKPhysicsContactの特定のプロパティのみを公開する単なる空のクラス定義のように見えますPKPhysicsContact

これは、SpriteKit チームの Objective-C ハックであり、Swift の強力なタイピングを壊しているように感じます。

ヘルプ?

いつでも戻ってくるようにするにはどうすればよいSKPhysicsContactですか?


テストするチェックを追加しましたSKPhysicsContact

let test = contact as Any
print("Test is: \(test)")
guard test is SKPhysicsContact else {
    return
}

タイプの不一致を正しくキャッチします。

実際、!!?を返すことは決してありません。SKPhysicsContact


Objective-C でこれを実行しようとしましたが (レスポンダーの提案に従って)、同じ結果が得られました。

Apple Dev Forumsでディスカッションを行っており、将来の回答を求める人に役立つ可能性があります。

参照用の Objective-C コードは次のとおりです。

@interface SKPhysicsContact (MatchingBodies)

- (NSArray *)bodiesMatchingCategory:(UInt32)category;

@end

@implementation SKPhysicsContact (MatchingBodies)

- (NSArray *)bodiesMatchingCategory:(UInt32)category {
    NSArray *bodies = @[self.bodyA, self.bodyB];

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(SKPhysicsBody *body, NSDictionary *bindings) {
        return (body.categoryBitMask & category) != 0;
    }];
    NSArray *matching = [bodies filteredArrayUsingPredicate:predicate];
    return matching;
}

@end

ここで呼び出されます:

-(void)didBeginContact:(SKPhysicsContact *)contact
{
    static const uint32_t MarbleContact = 0x1 <<1;  // 2
    static const uint32_t GoalContact = 0x1 <<2;    // 4

    SKPhysicsBody *ball = [contact bodiesMatchingCategory:MarbleContact].firstObject;
    NSLog(@"Ball: %@", ball);
    ...

このクラッシュを返します:

-[PKPhysicsContact bodiesMatchingCategory:]: unrecognized selector sent to instance 0x17dad9e0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PKPhysicsContact bodiesMatchingCategory:]: unrecognized selector sent to instance 0x17dad9e0'

Apple のバグレポートを追加、#23332190

4

1 に答える 1

5

この単純なコードで同じエラーが発生します。

extension SKPhysicsContact {
    func bodiesMatchingCategory(mask: UInt32) -> [SKPhysicsBody] {
        let bodies = [bodyA, bodyB]
        return bodies.filter { ($0.categoryBitMask & mask) != 0 }
    }
}

let contact = SKPhysicsContact()
let body = contact.bodiesMatchingCategory(0)

問題は、のタイプcontactPKPhysicsContact(お気づきのように) is であると明示的に指示した場合でもSKPhysicsContact、拡張子が on であることSKPhysicsContactです。これを機能させるには、拡張機能を作成できる必要がありますPKPhysicsContactSKPhysicsContactこのロジックから、現時点では拡張機能で機能するインスタンス メソッドはないと言えます。これは SpriteKit のバグだと思います。レーダーに報告する必要があります。クラスメソッドは、クラス自体で呼び出すため、引き続き機能します。

それまでの間、そのメソッドをシーンまたは別のオブジェクトに移動して、そこで正常に呼び出すことができるはずです。


記録として、これは Swift 固有の問題ではありません。上の Objective-C カテゴリで同じメソッドを作成するとSKPhysicsContact、同じクラッシュが発生します。

于 2015-10-29T19:52:59.510 に答える