didBeginContact передал PKPhyicsObject

У меня есть вспомогательный метод, который расширяет 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)
...

Иногда я получаю это сообщение об ошибке (например, 1 из 5), которое приводит к сбою приложения:

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

Я посмотрел вверх PKPhysicsContact и это часть частного фреймворка ( ссылка). SKPhysicsContact Похоже, это просто пустое определение класса, который раскрывает только определенные свойства PKPhysicsContact,

Я чувствую, что это взлом Objective-C в команде SpriteKit, который нарушает строгую типизацию Swift.

Помогите?

Как сделать так, чтобы я всегда получал SKPhysicsContact назад?


Я добавил чек, чтобы проверить SKPhysicsContact

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

Который правильно ловит несоответствие типов.

На самом деле, это никогда не возвращает SKPhysicsContact!!?


Я пытался сделать это в Objective-C (как подсказывает респондент), и я получаю тот же результат.

У меня есть дискуссия на форумах Apple Dev, которая может помочь будущим искателям ответов.

Вот код 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

1 ответ

Решение

Я получаю ту же ошибку с этим простым кодом:

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)

Проблема в том, тип contact является PKPhysicsContact (как вы заметили), даже когда вы явно говорите, что это SKPhysicsContactи расширение включено SKPhysicsContact, Вы должны быть в состоянии сделать расширение PKPhysicsContact чтобы это работало. Исходя из этой логики, мы можем сказать, что никакие методы экземпляра не будут работать в SKPhysicsContact расширения на данный момент. Я бы сказал, что это ошибка в SpriteKit, и вы должны подать радар. Методы класса по-прежнему работают, так как вы вызываете их для самого класса.

Между тем, вы должны иметь возможность переместить этот метод в вашу сцену или другой объект и успешно вызвать его там.


Для записи, это не специфическая проблема Swift. Если вы делаете тот же метод в категории Objective-C на SKPhysicsContact вы получите тот же сбой.

Другие вопросы по тегам