每天学一点Swift----面向对象下(八)

来源:互联网 发布:淘宝客服主管用的软件 编辑:程序博客网 时间:2024/05/22 13:34

十五.可选协议

1. Swift还支持在协议中定义定义可选成员要求(包括属性、方法、下标,不包括构造器)----是可选成员要求,不是可选成员。可选成员要求的意思是:该协议的实现类型既可以实现这些协议成员,也可以不实现这些协议成员。


2. 只要在协议成员前添加关键optional关键字即可定义可选协议。


3. 由于协议的实现者可以不实现可选协议的要求,因此程序面向对象编程时,调用可选协议的可选成员时,推荐使用可选链(需要在属性、方法、下标后添加问号)调用,这样可以避免当该成员没有被实现时导致的运行时错误,调用可选成员的返回值总是可选值。


4.由于可选协议主要是为了保持与Objective-C协议的兼容性,因此可选协议必须添加@objc修饰----@objc用于声明类、协议可以被Objective-C调用。即使该协议不打算被Objective-C调用,也必须添加@objc修饰。不仅如此,可选协议 只能 被类实现,不能被枚举、结构体实现,所以,可选协议一定是唯类协议。


5. 举个栗子: 

@objc protocol MyProtocol

{

  //定义可选属性

  optional var status : String {get}

  //定义可选方法

  optional func test(val : Int)

  //定义可选下标

  optional subscorpt(ids : Int) -> {get}

}


上面定义了一个协议,使用了@objc修饰,因此该协议一定是一个唯类协议,而且该协议可以包含可选成员。

既然MyProtocol协议的所有成员都是可选的,因此可以定义一个空类来实现该协议

//定义一个空类,实现MyProtocol协议,但并不实现该协议的任何成员

class EmptyClass : MyPtorocol

{}


6. 关联到3中的知识点,在使用可选协议调用可选属性、可选下标时可以不使用可选链----不管程序使用使用可选链,调用可选成员总是返回可选值。   使用可选协议调用可选方法时,Swift要求必须 使用可选链。


十六.输出实例和Printable协议

1. 假设有一个Person,实例为:var peron = Person(),print(person)输出Person实例后,将看到:PrintInstance.Person,这个结果没有太大的意义。


2. 如果希望输出实例时,能真正看到该实例的内部状态,可以让该实例实例实现Prinable协议,并实现呢协议中的description只读属性。


3. description只读属性是一个非常特殊的属性,它是一个自我描述属性,该属性的返回值通常用于实现这样一个功能:当程序直接输出该实例时,系统将输出该实例的自我描述信息,用于告诉外界该实例具有的状态信息。


4. 举个栗子:

class Person : Printable

{

   var name : String

   var age : Int

   init(name : String, age : Int)

   {

self.name = name

self.age = age

   }

   //Printable中的只读属性

   var description : String

   {

return "msg: (\name) and (\age)"

   }

}


则下面两个代码的结果完全相同:

print(person)

print(person.description)


十七.使用自定义类型作为字典的key

1. 前面学习字典的时候,总是使用系统的IntString等作为key。这里将要学习使用自定义类型作为字典的key


2. 在字典中,不允许出现相同的两个key。只要两个key满足一下两个条件,字典就会认为他们相等:

1)两个key通过==比较返回true

2)两个keyhashValue属性返回相等的整数。


3. 但是自定义类型的实例无法通过==进行比较,自定义类型的实例也没有hashValue属性,为了让自定义类型满足上述两个条件,自定义类型必须进行如下改造:

1)让自定义类型实现Equatable协议,并重载==比较运算符,是的自定义类型的实例可以通过==进行比较。

2)让自定义类型实现Hashable协议,并实现协议中的hashValue只读属性。实现hashValue只读属性时,应该和重载的==保持一致。也就是说,当两个实例通过==比较返回true时,两个实例的hashValue也应该相等。----实现Equatable协议,并重载==运算符实际上就是重新定义了一个名为==的函数,方法中的内容由自己提供认为相等的标准。


4. HashableEquatable协议都是Swift提供的协议,而且Hashable协议是Equatable的子协议,因此自定义类型只要实现Hashable协议即可。


5. 通常而言,正确地重载==运算符应该满足以下条件:

1)自反性:对任意xx==x应该返回true

2)对称性:对任意xy,如果x==y返回true,那么y==x也返回true

3)传递性:对任意xyz,如果x==y返回truey==z返回true,则x==z一定返回true

4)一致性:对任意xy,如果实例中用于等价比较的关键信息没有改变,那么无论x==y调用多少次,返回的结果都应该保持一致,


6.举个栗子:

class User : Equatable, Printable

{

   var name : String

   var pwd : String

   var age : Int

   init(name : String, pwd : String, age : Int)

   {

self.name = name

self.pwd = pwd

self.age = age

   }

   var hashValue : Int

   {

//根据namepwdhashValue来计算User实例的hashValue

//考虑到数据可能溢出,故此处采用溢出运算符

return name.hashValue &* 31 &+ pwd.hashValue

   }

   var description : String

   {

return "User{\(name),\(pwd),\(age)}"

   }


   //重载==运算符

   func == (lhs : User, rhs : Usr)

   {

return lhs.name == rhs.name && lhs.pwd == rhs.pwd

   }

}


上面的User类满足了上面3中所说的两个条件,因此这个类的实例可以作为字典的key


上一篇:每天学一点Swift----面向对象下(七)

下一篇:每天学一点Swift----面向对象下(九)

原创粉丝点击