当委托字段不被称为 `delegate` 时实现 `DelegateProxy` (RxSwift/RxCocoa)

Posted

技术标签:

【中文标题】当委托字段不被称为 `delegate` 时实现 `DelegateProxy` (RxSwift/RxCocoa)【英文标题】:Implementing `DelegateProxy` (RxSwift/RxCocoa) when delegate field is not called `delegate` 【发布时间】:2019-01-19 10:42:20 【问题描述】:

我需要一些有关DelegateProxy 实施的帮助。具体来说,当委托字段的名称与简单的delegate 不同时,实现它的正确方法是什么?如在SKPhysicsContactDelegate 中称为contactDelegate。我尝试定义一个计算值delegate,但它没有成功 - https://github.com/maxvol/RxSpriteKit/blob/master/Proxy/RxSKPhysicsContactDelegateProxy.swift

"DelegateProxy has no factory of <PKPhysicsWorld: 0x280b18990>. Implement DelegateProxy subclass for <PKPhysicsWorld: 0x280b18990> first." 失败 也许它甚至与委托字段名称无关,但这是我能找到的与正常工作的代理的唯一区别。

更新:哈!我刚刚注意到错误消息说PKPhysicsWorld,而不是SKPhysicsWorld。所以我的假设是,这与DelegateProxyFactory.createProxy 中的objectPKPhysicsWorld 而不是SKPhysicsWorld_factories[ObjectIdentifier(mirror.subjectType)] 返回nil 的事实有关。

【问题讨论】:

【参考方案1】:

您收到该错误的原因是您的 registerKnownImplementations() 函数没有运行。

以下要点应该有效:https://gist.github.com/dtartaglia/9f1f937628504ca56dbb1aac7d91df2b

代码也在下面,但要点可以保持最新:

//
//  SKPhysicsWorld+Rx.swift
//
//  Created by Daniel Tartaglia on 21 Jan 2019.
//  Copyright © 2019 Daniel Tartaglia. MIT License.
//

import RxSwift
import SpriteKit

public
extension Reactive where Base: SKPhysicsWorld 

    var didBegin: Observable<SKPhysicsContact> 
        return Observable.create  observer in
            physicsContatctDelegatesLock.lock(); defer  physicsContatctDelegatesLock.unlock() 
            let uuid = UUID()
            if let (delegate, beginners, enders) = physicsContatctDelegates[self.base] 
                var new = beginners
                new[uuid] = observer
                physicsContatctDelegates[self.base] = (delegate, new, enders)
            
            else 
                let delegate = PhysicsContactDelegate(for: self.base)
                self.base.contactDelegate = delegate
                physicsContatctDelegates[self.base] = (delegate, [uuid: observer], [:])
            

            return Disposables.create 
                physicsContatctDelegatesLock.lock(); defer  physicsContatctDelegatesLock.unlock() 
                let (delegate, beginners, enders) = physicsContatctDelegates[self.base]!
                var new = beginners
                new.removeValue(forKey: uuid)
                if new.isEmpty && enders.isEmpty 
                    physicsContatctDelegates.removeValue(forKey: self.base)
                
                else 
                    physicsContatctDelegates[self.base] = (delegate, new, enders)
                
            
        
    

    var didEnd: Observable<SKPhysicsContact> 
        return Observable.create  observer in
            physicsContatctDelegatesLock.lock(); defer  physicsContatctDelegatesLock.unlock() 
            let uuid = UUID()
            if let (delegate, beginners, enders) = physicsContatctDelegates[self.base] 
                var new = enders
                new[uuid] = observer
                physicsContatctDelegates[self.base] = (delegate, beginners, new)
            
            else 
                let delegate = PhysicsContactDelegate(for: self.base)
                self.base.contactDelegate = delegate
                physicsContatctDelegates[self.base] = (delegate, [:], [uuid: observer])
            

            return Disposables.create 
                physicsContatctDelegatesLock.lock(); defer  physicsContatctDelegatesLock.unlock() 
                let (delegate, beginners, enders) = physicsContatctDelegates[self.base]!
                var new = enders
                new.removeValue(forKey: uuid)
                if new.isEmpty && enders.isEmpty 
                    physicsContatctDelegates.removeValue(forKey: self.base)
                
                else 
                    physicsContatctDelegates[self.base] = (delegate, beginners, new)
                
            
        
    


private
class PhysicsContactDelegate: NSObject, SKPhysicsContactDelegate 

    init(for world: SKPhysicsWorld) 
        self.world = world
        super.init()
    

    func didBegin(_ contact: SKPhysicsContact) 
        physicsContatctDelegatesLock.lock(); defer  physicsContatctDelegatesLock.unlock() 
        let (_, beginners, _) = physicsContatctDelegates[world]!
        for each in beginners.values 
            each.onNext(contact)
        
    

    func didEnd(_ contact: SKPhysicsContact) 
        physicsContatctDelegatesLock.lock(); defer  physicsContatctDelegatesLock.unlock() 
        let (_, _, enders) = physicsContatctDelegates[world]!
        for each in enders.values 
            each.onNext(contact)
        
    

    let world: SKPhysicsWorld


private let physicsContatctDelegatesLock = NSRecursiveLock()
private var physicsContatctDelegates: [SKPhysicsWorld: (SKPhysicsContactDelegate, [UUID: AnyObserver<SKPhysicsContact>], [UUID: AnyObserver<SKPhysicsContact>])] = [:]

【讨论】:

不幸的是,没有任何区别。我的registerKnownImplementations() 被调用,但里面的内容 (self.register ... ) 失败了。 4.4.0;我的假设是这与DelegateProxyFactory.createProxy 中的objectPKPhysicsWorld 而不是SKPhysicsWorld_factories[ObjectIdentifier(mirror.subjectType)] 返回nil 的事实有关。 我刚刚在开发者论坛forums.developer.apple.com/thread/96994 中找到了这个。你是对的,这意味着你不能实现委托代理。还有其他方法,我会在今天晚些时候更新我的答案。 感谢您找到该主题。期待你的更新! 你去。老式的方式。 :-)

以上是关于当委托字段不被称为 `delegate` 时实现 `DelegateProxy` (RxSwift/RxCocoa)的主要内容,如果未能解决你的问题,请参考以下文章

iOS 委托代理与协议(Delegate and Protocol)

关于js模拟c#的Delegate(委托)实现

事件委托 EventHandler

C#委托-Delegate

C# 委托(Delegate)

直接与委托 - jQuery .on()