Swift 3, is the “.self” in a metatype issue actually correct?

前端 未结 1 1347
执笔经年
执笔经年 2021-01-21 00:59

I have an extension to walk up the view controller chain (even through container views, which is very handy)

public extension UIViewController   // go up to a ce         


        
1条回答
  •  迷失自我
    2021-01-21 01:41

    (Aside, NB, Swift3 needs the "!" on p.next: unfortunately I'm not sure exactly why.)

    Because .next returns an Optional, but p is not optional. This will crash if you run out of responders.

    1) It seems ... dangerous ... to change General to General.self - in fact is it safe and is the meaning the same as General in Swift <3 ?

    I'm surprised that worked in earlier versions of Swift without the .self, but yes, .self is required in order to directly reference a metatype. Referencing metatypes is somewhat rare in Swift, and can lead to surprising behaviors if done unintentionally, so it requires an extra piece of syntax to say "yes, I really mean the type."

    why is that a metatype? Did I "do something wrong" and make it ask for a metatype rather than just a type?

    You did this correctly.

    2) What the hell is a "metatype"?

    The type of a type. An instance of a metatype is a type. Consider:

    func f(x: Int)
    

    To call this, you pass an instance of Int. So similarly:

    func f(x: T.Type)
    

    To call this, you pass an instance of the metatype T.Type, which is a type.


    Unrelated, but I would probably rethink this code along these lines. First, it is convenient to be able to treat the responder chain as a sequence. Here's one way to do that:

    public extension UIResponder {
        public func nextResponders() -> AnySequence {
            guard let first = next else { return AnySequence([]) }
            return AnySequence(sequence(first: first, next: { $0.next }))
        }
    }
    

    Then getting the next responder that matches a type is cleaner and clearer IMO (and works on any responder chain):

    public extension UIResponder {
        public func firstResponder(ofType _: T.Type)-> T? {
            return nextResponders()
                .flatMap { $0 as? T }
                .first
        }
    }
    
    ...
    
    self.firstResponder(ofType: General.self)?.clickedHamburgerMenuButton()
    

    0 讨论(0)
提交回复
热议问题