- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
注:本小节总结协议以及依靠协议实现委托,这将在以后经常被使用。是一个非常重要的模块
看下官方的定义:协议定义了一个蓝图 , 规定了用来实现某一特定工作或者功能所必须的方法和属性,类、结构体、或者枚举类型都可以遵循协议, 并提供具体实现来完成协议定义的方法和功能 。 任意能够满足协议要求的类型都被成为遵循了这个协议
协议的关键字:protocol
协议的语法:
protocol Pro1{
//这里定义属性或者方法
}
要使一个类或者结构体遵循某个协议 , Class1: Pro1
只需要冒号加上协议名称就可以了 。 这时候这个类就必须实现协议中的属性和方法 。(可选的可以不实现,后面会说)
protocol Pro1{
var name:String{set get} //可读可写
var age:Int { get } //只读属性
static var status:Int {set get}
}
//遵循协议
struct Struct1 : Pro1 {
private var _name = ""
var name:String {
set{
_name = newValue
}
get{
return _name
}
}
var age = 18 //可以声明为可读可写的
static var status = 1 //类型方法。
}
class Class1: Pro1 {
var name = "class"
var age:Int{ return 19 } //也可以是只读
static var status = 0
}
这里可以看到遵循者实现协议的集中方式,包括可读可写的和只读的。注释非常清晰,就不再赘述。
在协议中你可以定义实例方法 , 也可以定义类方法 ,其方法和属性定义差不多。
protocol MethodPro{
func plus(a:Int , b:Int)->Int
static func toUpper(str:String)->String
}
class MethodClass: MethodPro {
func plus(a: Int, b: Int)->Int {
return a + b
}
class func toUpper(str: String)->String {
return str.uppercaseString
}
}
很简单的例子说明下 , 在协议中用static
在实现类里可以用static
或者 class
我们都知道,在结构体和枚举这种值类型的实例方法中 , 不能对自己的变量进行操作 , 如果一定要操作 ,就需要生命成变异方法 。 所在在协议中有时候也需要声明成变异方法让结构体或者媒体去实现 。(类实现的时候不需要加mutating)
protocol MulPro{
mutating func toggle();
}
enum Tog:MulPro{
case On , Off
mutating func toggle() {
switch self {
case On:
self = Off
case Off:
self = On
}
}
}
var t=Tog.Off
t.toggle()
print(t) //Tog.On
t.toggle()
print(t) //Tog.Off
注释很清楚就不用过多解释了
协议也可以要求自己的遵循者实现指定的构造器。
所以在协议中也可以这么写,
protocol A{
init(val:Int)
}
实现这个协议的必须有这样的构造器,可以是指定构造器或者便利构造器,都必须加上required
修饰符 ,这样 在所以继承这个类的子类也都必须实现这个构造器。(关于各种构造器的解释 看我以前的构造过程那个文章)
class B: A {
required init(val:Int){
}
}
注:如果类已经标记为final ,则不需要required修饰符 ,final类不能有子类
如果在协议中定义的是一个可失败构造器,那么在遵循者中必须实现可失败构造器 后者 非可失败
协议可以当做一个类型来时候 , 调用调用协议的方法调用的是其实现类的方法
有时候我们需要在协议中定义的方法 , 有得遵循者需要实现 , 有得不是必须去实现的。这时候就可以使用可选类型。
可选协议只能在含有 @objc
前缀的协议中生效,而且可选协议只能被类去实现 。
@objc protocol Op{
optional var name:String{set get} //可选类型
optional func play()
var age:Int{get}
}
这个协议定义了一个可选属性和一个可选方法还有一个age属性 , 在实现他得类中只有age是必须实现的 。其他两个都是可选的 。
protocol SayHelloDelegate{
func sayHello(name:String);
}
class ClassA {
var delegate:SayHelloDelegate?
var name = "lucy"
func play(){
delegate?.sayHello(name);
}
}
class ClassB:SayHelloDelegate {
var name="lily"
func sayHello(name:String) {
print("\(name) 请 \(self.name) 帮她 say Hello");
}
}
我们这里定义了一个协议 ,有个很简单的方法,sayHello
,在A中声明了这个协议变量 ,使用了其方法 ,但这个方法却交给B去实现 。这就是一个很简单的代理模式
var ca = ClassA();
var cb = ClassB()
ca.delegate = cb
//B代理A去实现方法
ca.play(); //lucy 请 lily 帮她 say Hello
这是一个很简单的例子 ,但这个模式一会肯定会有很复杂的用法
扩展用extension
关键字 ,后面应该会加上这个的讲解
protocol HTMLFormat{
func asHtml(str:String)->String
}
//可以对ClassB扩展实现协议
extension ClassB:HTMLFormat{
func asHtml(str: String)->String {
return "<html>\(str)</html>"
}
}
这里我们让我们前面看得ClassB
再次实现这个协议 。然后他就一共实现了两个协议 , 一个sayHello 一个 hmtl的
var cb1 = ClassB();
cb1.asHtml("dog") //<html>dog</html>
cb1.sayHello("aaa") //aaa 请 lily 帮她 say Hello
这时候这两个方法就都可以用了
当然我们的协议也是可以继承的 。这里就不再示例。
protocol C : class{
func say();
}
class D: C{
func say(){
print("hello word")
}
}
看一看知道怎么回事就行了,就是在结构体和枚举里面不能用得协议
protocol N{
var age:Int{set get}
}
class F:M,N {
var name = "zhangsan"
var age = 18
}
这里我们定义了两个协议 ,F 遵循了这两个协议 ,这时候 我们有个方法需要传入的参数类型是遵循了这两个协议的实例
func happy(mn:protocol<M,N>){
print("\(mn.name) 今年 \(mn.age) 岁了,非常开心!!")
}
var f=F()
happy(f) //zhangsan 今年 18 岁了,非常开心!!
这里F是满足这两个协议的
你可以使用 is``as?``as
来检测摸个实例是否遵循某个协议
print(f is M) //true
let c = f as M
print(c) //F
关于is
,as
等得用法 可以看上一节类型转换
extension M{
func sayGoodBye(){
print("good-bye")
}
}
在扩展协议中提供默认实现 ,如果在遵循者中实现了此协议,则使用遵循者中的实现
有没有办法在 .swift 文件(编译成 .swift 模块)中声明函数,如下所示: 你好.swift func hello_world() { println("hello world")
我正在尝试使用 xmpp_messenger_ios 和 XMPPFramework 在 iOS 上执行 MUC 这是加入房间的代码。 func createOrJoinRoomOnXMPP()
我想在我的应用程序上创建一个 3D Touch 快捷方式,我已经完成了有关快捷方式本身的所有操作,它显示正确,带有文本和图标。 当我运行这个快捷方式时,我的应用程序崩溃了,因为 AppDelegate
我的代码如下: let assetTag = Expression("asset_tag") let query2 = mdm.select(mdm[assetTag],os, mac, lastRe
我的 swift 代码如下所示 Family.arrayTuple:[(String,String)]? = [] Family.arrayTupleStorage:String? Family.ar
这是我的 JSON,当我读取 ord 和 uniq 数据时出现错误 let response2 : [String: Any] = ["Response":["status":"SUCCESS","
我想将 swift 扩展文件移动到 swift 包中。但是,将文件移动到 swift 包后,我遇到了这种错误: "Type 'NSAttributedString' has no member 'ma
使用CocoaPods,我们可以设置以下配置: pod 'SourceModel', :configurations => ['Debug'] 有什么方法可以用 Swift Package Manag
我正在 Xcode 中开发一个 swift 项目。我将其称为主要项目。我大部分都在工作。我在日期选择器、日期范围和日期数学方面遇到了麻烦,因此我开始了另一个名为 StarEndDate 的项目,其中只
这是 ObjectiveC 代码: CCSprite *progress = [CCSprite spriteWithImageNamed:@"progress.png"]; mProgressBar
我正在创建一个命令行工具,在 Xcode 中使用 Swift。我想使用一个类似于 grunt 的配置文件确实如此,但我希望它是像 Swift 包管理器的 package.swift 文件那样的快速代码
我假设这意味着使用系统上安装的任何 swift 运行脚本:#!/usr/bin/swift 如何指定脚本适用的解释器版本? 最佳答案 Cato可用于此: #!/usr/bin/env cato 1.2
代码说完全没问题,没有错误,但是当我去运行模拟器的时候,会出现这样的字样: (Swift.LazyMapCollection (_base:[ ] 我正在尝试创建一个显示报价的报价应用。 这是导入
是否可以在运行 Swift(例如 Perfect、Vapor、Kitura 等)的服务器上使用 RealmSwift 并使用它来存储数据? (我正在考虑尝试将其作为另一种解决方案的替代方案,例如 no
我刚开始学习编程,正在尝试完成 Swift 编程书中的实验。 它要求““编写一个函数,通过比较两个 Rank 值的原始值来比较它们。” enum Rank: Int { case Ace = 1 ca
在您将此问题标记为重复之前,我检查了 this question 它对我不起作用。 如何修复这个错误: error: SWIFT_VERSION '5.0' is unsupported, suppo
从 Xcode 9.3 开始,我在我的模型中使用“Swift.ImplicitlyUnwrappedOptional.some”包裹了我的字符串变量 我不知道这是怎么发生的,但它毁了我的应用程序! 我
这个问题在这里已经有了答案: How to include .swift file from other .swift file in an immediate mode? (2 个答案) 关闭 6
我正在使用 Swift Package Manager 创建一个应用程序,我需要知道构建项目的配置,即 Debug 或 Release。我试图避免使用 .xcodeproj 文件。请有人让我知道这是否
有一个带有函数定义的文件bar.swift: func bar() { println("bar") } 以及一个以立即模式运行的脚本foo.swift: #!/usr/bin/xcrun s
我是一名优秀的程序员,十分优秀!