美文网首页
type(of: )、.Type、AnyObject、AnyCl

type(of: )、.Type、AnyObject、AnyCl

作者: 黑色蚂蚁_MGL | 来源:发表于2020-09-09 23:15 被阅读0次

    type(of: ) 获取参数类型的方法

    1. 下面的代码中咱们声明了一个类ClassA,然后用ClassA创建了两个实例a1、a2,咱们用type(of: )方法打印这两个实例的类型,结果打印结果都是ClassA。

      • 因为a1、a2是用ClassA创建出来的,所以a1、a2 是ClassA类型这个结果是符合咱们预期的。

      • 但是a1和a2创建时,有点小差别,就是a1没有声明类型,a2明确的声明了是ClassA类型,咱们知道swift语言中,没声明的话,会自动根据后面的值确定类型,所以a1会被默认声明成ClassA类型

        class ClassA {
            var value = 10
        }
        
        let a1 = ClassA()
        let a2: ClassA = ClassA()
        print(type(of: a1))
        print(type(of: a2))
        
        打印结果
        ClassA
        ClassA
        
    2. 咱们再看一下官方是怎么介绍 type(of:) 的:You can use the type(of:) function to find the dynamic type of a value, particularly when the dynamic type is different from the static type.就是获取传入参数的动态类型,尤其是传入参数的静态类型和动态不一致时。

      • 什么是静态类型,什么是动态类型
        静态类型可以简单的理解为,你从外观可以看出来的类型,也就是这个变量声明时的类型,就和上面let a2: ClassA说自己是中a2说自己是ClassA类型,

        动态类型就是这个变量实际是哪个类型的,比如上面let a1 = ClassA() =号后面是啥类型,他就是啥类型

      • 举个例子

        class ClassA {
            var value = 10
        }
        
        class ClassB: ClassA {
            var value2 = 20
        }
        
        let a: ClassA = ClassB()
        print(type(of: a))
        
        打印结果
        ClassB
        

        从这行代码可以看出let a: ClassA = ClassB()a的静态类型是ClassA(也就是声明时给自己定的类型),但是a的动态类型是ClassB,也就是实际的类型。就类似一个瓶子上贴着茅台酒的标签,里装的是北京二锅头。但是type(of:)就是获取动态(真实)类型的

    3. type(of: )获得的类型是等价于直接写的类型

      • 比如下面,type(of: a) 和 ClassA是一样的
      class ClassA {
         var value = 10
         class func printName() {
            print("----ClassA")
          }
       }
      
      let a: ClassA = ClassA()
      type(of: a).printName()
      ClassA.printName()
      
      打印结果
      ----ClassA
      ----ClassA
      
    • 官方的例子是这个
      class Smiley {
            class var text: String {
                return ":)"
            }
        }
      
        class EmojiSmiley: Smiley {
             override class var text: String {
                return "😀"
            }
        }
      
        func printSmileyInfo(_ value: Smiley) {
            let smileyType = type(of: value)
            print("Smile!", smileyType.text)
        }
      
        let emojiSmiley = EmojiSmiley()
        printSmileyInfo(emojiSmiley)
        // Smile! 😀
      
    1. 注意的点
      type(of:)不仅可以用在像是class, structure, enumeration类、结构体、枚举等这种具体类型,也可以用于protocol协议这种有点虚拟的类型,例如下面(咱们可以先忽略 .self和.Protocol 后面会讲到,这里只是说明,参数可以是协议类型)
      protocol protocolA {
       
      }
      print(type(of: protocolA.self))
      
      打印结果
      protocolA.Protocol
      
      
      但是有个比较特殊的情况是:一个实例故意把自己说成是协议类型(也就是静态类型是协议),然后将这个参数通过一个泛型函数传进去,type(of:)会出来和预期不一样的结果,感兴趣的可以看看官方说明

    .Type 是啥

    1.说这些东西之前咱们先看一个生活中的例子,大家都见过这玩意吧, 00后的就不确定了 ~ ,90、80后应该都见过鱼模具,过年时,拿出这个模具里面放上面团做几个好看一点的

    咱们用这个鱼模具可以做出很多个鱼,如下图

    那这些模具是怎么来的呢,有可能是3D打印机打印的

    3D打印机.jpg

    2.看到上面这个例子,咱们应该清楚

    • 鱼是通过鱼的模具做出来的,鱼的模具是用3D打印机做的,3D打印机是别的机器造出来的等等。一个东西都有它的由来,不是凭空出现的

    • 同理咱们再用上面的ClassA举例,a1是用ClassA初始化来的,就好比鱼是用鱼模具做出来的,那ClassA是怎么来的呢(鱼模具是怎么来的呢),咱们先用type(of:)打印一下看看,看下面的代码,得知ClassA是ClassA.Type类型,也就是ClassA是由ClassA.Type创造的,因为没有具体的名称表示,所以就直接在ClassA后面加上个Type吧。那问题来了ClassA.Type是由啥创造出来的呢,很明显是ClassA.Type.Type,可以自己打印看看结果(注意下面的.self可以忽略,可以以当做没写.self。后面会说明.self是干啥的)

       class ClassA {
          var value = 10
       }
       print(type(of: ClassA.self))
      
       打印结果
       ClassA.Type
      
    • 所以说x.Type 是指x的类型,通俗点就是指:是谁创造了x 。咱们举个例子,继续用ClassA举🌰,看下面的代码,这种方法咱们经常见到testType1(value: ClassA)传入的参数类型是ClassA。也就是说value的类型是ClassA,谁的类型是ClassA,a1就是,所以testType1(value: a1)
      咱们再看testType2(value: ClassA.Type)这个方法要求传入的参数类型是ClassA.Type,谁的类型是呢,那就是ClassA的类型是ClassA.Type,所以testType2(value: ClassA.self)

      class ClassA {
          var value = 10
       
          func test1() {
          }
       
          class func test2() {
          }
      }
      
      func testType1(value: ClassA) {
           
       }
       
       func testType2(value: ClassA.Type) {
           
       }
      
      let a1 = ClassA()
      testType1(value: a1)
      testType2(value: ClassA.self)
      

    咱们可以理解为,判断一个参数的类型,就是判断这个参数是由啥模板创建出来的。"Hello, Type"是由String模板创建出来的,咱们用类举一个例子,ClassA就是咱们声明了一个类(模板),用ClassA这个模板创建了一个a,所以a的类型就是ClassA(创建a的模板)

    首先定义一个字符串var str = "Hello, type"
    当我问str是什么类型时,咱们都会说是String类型,这就是type(of: )的作用:告诉咱们传入的参数属于啥类型,如下面的例子

    var str = "Hello, Type"
    print(type(of: str))
    print(type(of: "Hello, Type"))
    
    打印结果:
    String
    String
    

    怎么理解呢,就是咱们声明了一个类ClassA(就类似上面说的鱼模具),然后创建了两个实例a1、a2(类似上面说的),type(of: )方法就是获取传入的参数是由哪个模具创造出来的

    AnyObject

    官方是怎么介绍的呢:can be used as the concrete type for an
    instance of any class, class type, or class-only protocol
    可以用来表示类实例,类,和类专属的协议。也就是只和类相关的,有的文章说用于表示类实例的,这种说法不严谨,后面会说到

    1. 表示 "实例类型"
    • 比如用AnyObject来表示Swift的实例类型。实例的类型是啥,换种说法就是a1的类型(ClassA),说白了就是代表 "类",如下面的代码,AnyObject就是代替了ClassA

      class ClassA {
      
      }
      let aaa: AnyObject = ClassA()
      
    • 还可以表示OC中的实例类型,因为在OC中NSString、NSNumber都是类

      let s: AnyObject = "This is a bridged string." as NSString
      let v: AnyObject = 100 as NSNumber
      
      
    • 当用到这些实例的时候,可以用as 来尝试转成对应的类型

      if let message = s as? String {
          print("Successful cast to String: \(message)")
      }
      Prints "Successful cast to String: This is a bridged string."
      
    2 可以调用所有用@objc修饰的方法,不管是不是自己的方法都可以调用
    • 例如声明两个类 ClassA 、ClassB
      class ClassA {
       
          @objc func printMessageA1() {
             print("A1-----")
          }
       
          @objc func printMessageA2() {
              print("A2-----")
          }
      }
      
      class ClassB {
       
          @objc func printMessageB1() {
              print("B1-----")
          }
      
          @objc func printMessageB2() {
              print("B2-----")
          }
      }
      
    • 当我用AnyObject表示的实例进行方法调用时,会联想出所有带@objc的方法 方法调用
    • 需要咱们注意到联想出来的方法后面都是带有!的,说明调用的方法是可选类型,就是可以用也可以用 。但是默认是强制解析的。当咱们不确定这个方法是不是属于自己时,建议用否则会崩溃
      调用不是自己的方法,并且使用了强制解析会崩溃
    3 AnyObject不仅可以表示实例类型也可以代表类的类型(不常用)
    • 定义ClassA,声明一个类方法,只有类可以调用
    class ClassA {  
        @objc class func printMessageA3() {
            print("A3-----")
        }
    }
    
    • 用AnyObject表示一个类的类型,然后调用类方法
    let calss: AnyObject = ClassA.self
    (calss as? ClassA.Type)?.printMessageA3()
    
    打印结果
    A3-----
    

    AnyClass

    • 文档中是这么定义的public typealias AnyClass = AnyObject.Type也就是一般用于表示类的类型

    • 怎么用呢,咱们还是用之前的类ClassA为例

      class ClassA {
          class func printMessageA3() {
             print("A3-----")
          }
      }
      let anyClass: AnyClass = ClassA.self
      (anyClass as? ClassA.Type)?.printMessageA3()
      
      打印结果
      A3-----
      
    • AnyClass类型的变量可以调用所有用@objc声明的类方法,举个🌰,声明两个类ClassA、ClassB。分别有两个类方法printMessageA3、printMessageB3。然后定义一个anyClass,就会看到这个anyClass可以调用所有带有@objc的类方法。当然还是会默认强制解包,这个咱们需要注意,不确定的用比较好

      class ClassA {
       
          @objc class func printMessageA3() {
              print("A3-----")
          }
      }
      
      class ClassB {
       
          @objc class func printMessageB3() {
              print("B3-----")
          }
      }
      
      let anyClass: AnyClass = ClassA.self
      anyClass.printMessageA3()
      anyClass.printMessageB3?()
      
      
      可以调用所有带有@objc的类方法

    .self

    • .self用在实例后面代表这个实例本身。两种调用printMessageA1()方式,打印的结果是一样的,只是平时可以省略不需要写
      class ClassA {
       
         func printMessageA1() {
             print("A1-----")
         }
      }
      
      let a: ClassA = ClassA()
      
      a.printMessageA1()
      a.self.printMessageA1()
      
    • 用在类型后面代表类型本身,也就是变量代表的类型
      ClassA.self就是代表ClassA类型,一般用在函数的参数是类型时。比如需要传一个参数,参数的类型是ClassA.Type,什么参数的类型是ClassA.Type,那就是ClassA类型("类型"、"的类型"表述的东西是不一样的)
      class ClassA {
       
          func testType(value: ClassA.Type) {
           
          }
      }
      
      let a: ClassA = ClassA()
      a.testType(value: ClassA.self)
      

    比如tableview的注册cell的方法,参数类型是AnyClass,谁的类型是AnyClass ,那就是UITableViewCell类型

    func register(AnyClass?, forCellReuseIdentifier: String)
    
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
    

    总结

    以ClassA、Int为例,则他们的等级就是如下,可以和最开始说的模具联系起来

    class ClassA {
    
    }
    
    let a = ClassA()
    
    
    一级 二级 三级 四级
    a ClassA ClassA.Type ClassA.Type.Type
    5 Int Int.Type Int.Type.Type
    AnyObject在这级 AnyClass在这级
    有啥不对的,欢迎批评指正

    相关文章

      网友评论

          本文标题:type(of: )、.Type、AnyObject、AnyCl

          本文链接:https://www.haomeiwen.com/subject/rxuksktx.html