Swift语言中的一些访问控制设置详解

限制访问代码块,模块和抽象通过访问控制来完成。类,结构和枚举可以根据自己的属性,方法,初始化函数和下标来通过访问控制机制进行访问。常量,变量和函数的协议限制,并允许通过访问控制来访问全局和局部变量。应用于属性,类型及函数的访问控制可以被称为“实体”。

访问控制模型是基于模块和源文件的。

模块定义为代码分配一个单独的单元,并且可以使用import 关键字导入。源文件被定义为一个单一的源代码文件,模块可访问多种类型和函数。

三种不同的访问级别是由 Swift 语言提供。它们分别是 Public, Internal 和 Private 访问。

语法

代码如下:

public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

对于函数类型的访问控制
某些函数可能有参数在函数声明中但没有任何返回值。下面的程序声明 a 和 b 作为参数传递给sum()函数。内部函数本身为参数a和b的值是通过调用所述通过调用函数 sum(),其值被打印从而不用返回值。为了使函数的返回类型为私有,声明函数使用 private 修饰整体访问级别。

代码如下:

private func sum(a: Int, b: Int) {
   let a = a + b
   let b = a - b
   println(a, b)
}

sum(20, 10)
sum(40,10)
sum(24,6)

当我们使用 playground 运行上面的程序,得到以下结果

(30, 20)
(50, 40)
(30, 24)

对于枚举类型的访问控制


代码如下:

public enum Student{
   case Name(String)
   case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
   case .Name(let studName):
      println("Student name is: \(studName).")
   case .Mark(let Mark1, let Mark2, let Mark3):
      println("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
   default:
      println("Nothing")
}

当我们使用 playground 运行上面的程序,得到以下结果

Student Marks are: 98,97,95

枚举在Swift语言中将自动接收枚举个体并都具有相同的访问级别。例如,考虑访问固定于三个科目枚举名称,学生的名字和标记被声明为 student 而存在于枚举类中的成员都属于字符串数据类型名称,标记表示为 mark1, mark2 和 mark3 数据类型为整数。要访问无论是学生名称或标记分数。 现在,如果被执行 Switch case 块将打印学生姓名,否则它将打印由学生固定的标记。如果这两个条件都失败默认块将被执行。

子类访问控制
Swift 允许用户子类,可以在当前访问上下文存取的任何类。子类不能比其超类有更高的访问级别。 用户限制一个公共子类写入一个内部超类。

代码如下:

public class cricket {
      private func print() {
         println("Welcome to Swift Super Class")
   }
}

internal class tennis: cricket  {
   override internal func print() {
      println("Welcome to Swift Sub Class")
   }
}

let cricinstance = cricket()
cricinstance.print()

let tennisinstance = tennis()
tennisinstance.print()

当我们使用 playground 运行上面的程序,得到以下结果

Welcome to Swift Super Class
Welcome to Swift Sub Class

常量,变量,属性和下标访问控制
Swift 常量,变量或属性不能被定义比其类型更公开。这是无效一个 public 属性与 private 类型的写法。同样,下标不能超过其索引或返回类型更公开。

当一个常量,变量,属性或下标使用了一个私有类型,则常量,变量,属性或下标,也必须标记为私有:

代码如下:

private var privateInstance = SomePrivateClass()

Getters 和 Setters
getter和setter常量,变量,属性和标自动接收它们属于相同的访问级别的常量,变量,属性或下标。

代码如下:

class Samplepgm {
   private var counter: Int = 0{
      willSet(newTotal){
         println("Total Counter is: \(newTotal)")
      }
      didSet{
         if counter > oldValue {
            println("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

当我们使用 playground 运行上面的程序,得到以下结果

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

访问控制的初始化和默认初始化器
自定义初始化函数可分配的接入级别小于或等于它们初始化的类型。一个必需的初始化必须具有相同的访问级别,因为它们和类相同。一个初始化的参数的类型不能比初始化自己的访问级别更私密(更高)。

声明每个和初始化每个子类, “required” 关键字需要在init()函数之前定义。

代码如下:

class classA {
   required init() {
      var a = 10
      println(a)
   }
}

class classB: classA {
   required init() {
      var b = 30
      println(b)
   }
}

let res = classA()
let print = classB()

当我们使用 playground 运行上面的程序,得到以下结果

10
30
10

默认初始化具有相同的访问级别,因为它初始化,除非该类型被定义为公共类型。 当默认初始化定义为公共它被认为是内部的。当用户需要一个公共类型在另一个模块中的一个无参数初始化进行初始化,明确提供一个公共的无参数初始化作为类型定义的一部分。

对于协议的访问控制
当我们定义一个新的协议,从现有的协议继承的功能,既有声明相同的访问级别以相互继承属性。Swift 访问控制允许用户定义 “public” 协议,它继承自 “internal” 的协议。

代码如下:

public protocol tcpprotocol {
   init(no1: Int)
}

public class mainClass {
   var no1: Int // local storage
   init(no1: Int) {
      self.no1 = no1 // initialization
   }
}

class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }

// Requires only one parameter for convenient method
   required override convenience init(no1: Int)  {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

println("res is: \(res.no1)")
println("res is: \(print.no1)")
println("res is: \(print.no2)")

当我们使用 playground 运行上面的程序,得到以下结果

res is: 20
res is: 30
res is: 50

扩展访问控制
当用户使用扩展来添加协议的一致性,Swift 不允许用户为扩展提供一个明确的访问级别修饰符。对于在每个协议的扩展,要求实现的默认访问级别设置自己的协议访问级别。

对于泛型访问控制
泛型允许用户指定最小访问级别来访问类型约束其类型参数。

代码如下:

public struct TOS<T> {
   var items = [T]()
   private mutating func push(item: T) {
      items.append(item)
   }

mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS<String>()
tos.push("Swift")
println(tos.items)

tos.push("Generics")
println(tos.items)

tos.push("Type Parameters")
println(tos.items)

tos.push("Naming Type Parameters")
println(tos.items)
let deletetos = tos.pop()

当我们使用 playground 运行上面的程序,得到以下结果

[Swift]
[Swift, Generics]
[Swift, Generics, Type Parameters]
[Swift, Generics, Type Parameters, Naming Type Parameters]

对于类型别名访问控制
用户可以定义类型别名对待不同的访问控制类型。 相同的访问级别或不同的访问级别可以由用户定义。当类型别名为 “private” 及其相关成员可以声明为 “private,内部 public 类型 ”。当类型别名是公共成员不能是别名为 “internal” 或 “private” 的名称

定义任何类型别名被视为用于不同类型的访问控制的目的。一个类型别名可以具有小于或等于它的一个访问级别别名的类型的访问级别。例如,private类型别名可以别名为 private, internal, 或 public,而 public 类型别名不能别名为 internal 或 private 类型。

代码如下:

public protocol Container {
   typealias ItemType
   mutating func append(item: ItemType)
      var count: Int { get }
      subscript(i: Int) -> ItemType { get }
}

struct Stack<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }

mutating func pop() -> T {
      return items.removeLast()
   }

// conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item)
   }
  
   var count: Int {
      return items.count
   }

subscript(i: Int) -> T {
      return items[i]
   }
}

func allItemsMatch<
   C1: Container, C2: Container
   where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
   (someContainer: C1, anotherContainer: C2) -> Bool {
   // check that both containers contain the same number of items
   if someContainer.count != anotherContainer.count {
      return false
   }

// check each pair of items to see if they are equivalent
   for i in 0..<someContainer.count {
      if someContainer[i] != anotherContainer[i] {
         return false
      }
   }

// all items match, so return true
   return true
}

var tos = Stack<String>()
tos.push("Swift")
println(tos.items)

tos.push("Generics")
println(tos.items)

tos.push("Where Clause")
println(tos.items)

var eos = ["Swift", "Generics", "Where Clause"]
println(eos)

当我们使用 playground 运行上面的程序,得到以下结果

[Swift]
[Swift, Generics]
[Swift, Generics, Where Clause]
[Swift, Generics, Where Clause]
(0)

相关推荐

  • Swift 访问权限的资料整理

    Swift 访问权限 1>internal :内部的, 1.默认情况下所有的类的属性&方法的访问权限都是internal       2.若本模块(项目/包/target)中可以访问 2> private:私有的 1.只有在本类中可以访问 3> open 公开的 1.可以跨模块(包/target)都是可以访问的 4> fileprivate  swift3.0 1.只要在本文件中都是可以进行访问的 示例代码: import UIKit /* 1>internal :内

  • Swift学习教程之访问控制详解

    前言 本文主要给大家介绍了关于Swift访问控制的相关内容,访问控制对访问你的其他代码源文件和模块部分进行了约束.这个特性允许你隐藏你的代码实现,并且指定通过其可以访问和使用该代码的优选接口. class,structure 和 enumeration 都可以指定访问级别,当然,property,method,initializer 和 属于这里类型的 subscript.protocol 可以限制到某个上下文,全局变量,变量和函数也可以. 另外,Swift 也提供默认的使用级别给典型的使用场景

  • Swift中的访问控制和protected

    原文再续,书折第一回. 很多其他编程语言都有一种"protected"设定,可以限制某些类方法只能被它的子类所使用. Swift支持了访问控制后,大家给我们的反馈都很不错.而有的开发者问我们:"为什么Swift没有类似protected的选项?" 当我们在设计Swift访问控制的不同等级时,我们认为有两种主要场景: ●在一个APP里:隐藏某个类的私密细节. ●在一个开源框架里:不让导入这个框架的APP,随便接触框架的内部实现细节. 上面的两种常见情况,对应着priv

  • 详解Swift中的下标访问用法

    Swift中的Array,Dictionary类型可以通过下标或者键值的方式来进行数据的访问,实际上在Swift的语法中,下标可以定义在类.结构体.枚举中.开发者可以通过下标的方式来对属性进行访问而不用使用专门的存取方法.并且定义的下标不限于一维,开发者可以定义多维的下标来满足需求. 下标的语法结构 下标使用subscript来定义,其有些类似于方法,参数和返回值本别作为下标入参和通过下标所取的值.但是在subscript实现部分,又十分类似于计算属性,其需要实现一个get块和可选实现一个set

  • 深入理解Swift中的访问控制关键字

    前言 在Swift3.0以前有三种访问控制关键字,分别是private.internal和public.而在swift3以后,又在原来的基础上增加了两种访问控制关键字:fileprivate和open.他们可以看作是private和public的进一步细分.下面是各个修饰符的区别以及访问权限排序. 各个修饰符的区别 private swift3.0 private访问级别所修饰的属性或者方法只能在当前类里访问. class A { private func test() { print("thi

  • Swift语言中的一些访问控制设置详解

    限制访问代码块,模块和抽象通过访问控制来完成.类,结构和枚举可以根据自己的属性,方法,初始化函数和下标来通过访问控制机制进行访问.常量,变量和函数的协议限制,并允许通过访问控制来访问全局和局部变量.应用于属性,类型及函数的访问控制可以被称为"实体". 访问控制模型是基于模块和源文件的. 模块定义为代码分配一个单独的单元,并且可以使用import 关键字导入.源文件被定义为一个单一的源代码文件,模块可访问多种类型和函数. 三种不同的访问级别是由 Swift 语言提供.它们分别是 Publ

  • Kotlin 语言中调用 JavaScript 方法实例详解

    Kotlin 语言中调用 JavaScript 方法实例详解 Kotlin 已被设计为能够与 Java 平台轻松互操作.它将 Java 类视为 Kotlin 类,并且 Java 也将 Kotlin 类视为 Java 类.但是,JavaScript 是一种动态类型语言,这意味着它不会在编译期检查类型.你可以通过动态类型在 Kotlin 中自由地与 JavaScript 交流,但是如果你想要 Kotlin 类型系统的全部威力 ,你可以为 JavaScript 库创建 Kotlin 头文件. 内联 J

  • java 中file.encoding的设置详解

    java 中file.encoding的设置详解 昨天有人在讨论关于设置System的property,file.encoding 修改defaultcharset无效 Properties pps=System.getProperties(); pps.setProperty("file.encoding","ISO-8859-1"); 在java中,如果没有指定charset的时候,比如new String(byte[] bytes),都会调用Charset.d

  • Java语言中的内存泄露代码详解

    Java的一个重要特性就是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己来释放内存.理论上Java中所有不会再被利用的对象所占用的内存,都可以被GC回收,但是Java也存在内存泄露,但它的表现与C++不同. JAVA中的内存管理 要了解Java中的内存泄露,首先就得知道Java中的内存是如何管理的. 在Java程序中,我们通常使用new为对象分配内存,而这些内存空间都在堆(Heap)上. 下面看一个示例: public class Simple { public static vo

  • C语言中的正则表达式使用示例详解

    正则表达式,又称正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE).正则表达式是使用单个字符串来描述.匹配一系列符合某个句法规则的字符串. 在c语言中,用regcomp.regexec.regfree 和regerror处理正则表达式.处理正则表达式分三步: 编译正则表达式,regcomp: 匹配正则表达式,regexec: 释放正则表达式,regfree. 函数原型 /* 函数说明:Regcomp将正则表达式字符串regex编译

  • Go语言中的数据竞争模式详解

    目录 前言 Go在goroutine中通过引用来透明地捕获自由变量 切片会产生难以诊断的数据竞争 并发访问Go内置的.不安全的线程映射会导致频繁的数据竞争 Go开发人员常在pass-by-value时犯错并导致non-trivial的数据竞争 消息传递(通道)和共享内存的混合使用使代码变得复杂且易受数据竞争的影响 Add和Done方法的错误放置会导致数据竞争 并发运行测试会导致产品或测试代码中的数据竞争 小结 前言 本文主要基于在Uber的Go monorepo中发现的各种数据竞争模式,分析了其

  • C语言中联合体union的实例详解

     C语言中联合体union的实例详解 1.定义: union(int i, short s, char c) un; un.i = 3; printf("i=%d",un.i); printf("length = %d\n",sizeof(un);//==4,有最大的变量来决定 2.相当与java里的List T类型 3.数据交换 void swap(int *p , int *q){ int temp = *p; *p = *q; *q = temp; } 4.打

  • C语言中二级指针的实例详解

    C语言中二级指针的实例详解 用图说明 示例代码: #include <stdio.h> int main(int argc, const char * argv[]) { // int a = 5; int *p1 = &a; //-打印地址-----地址相同--------------- printf("&a = %p\n", &a);// printf("p1 = %p\n", p1);// int **p2 = &p

  • C语言中强制地址跳转详解

    C语言中强制地址跳转详解 #define jump(TargetAddr ) (*((void(*)())(TargetAddr))() 第一个(( void( * )(  )) ,意思为强制类型转换为一个无形参,无返回值的函数指针,(*(TargetAddr))为跳转地址,但是函数指针变量不能为常数所以要加((void( * )(  )) 进行强制类型转换.最后一个()为执行的意思. 整一条指定的目的是为了跳转到一个绝对地址执行函数. 1.在单片机中可以实现软件复位,比如跳转到0地址. 2.如

  • C语言中指针和数组试题详解分析

    目录 数组题: 程序一(一维数组): 字符数组 程序二(字符数组): 程序三(字符数组): 程序四(字符数组): 程序五(字符数组): 二维数组 程序六( 二维数组): 指针题 程序七( 指针): 程序八( 指针): 程序九( 指针): 程序十( 指针): 程序十( 图): 程序十一( 指针): 程序十二( 指针): 程序十三( 指针): 指针 和 数组 试题解析 小编,在这里想说一下,c语言的最后一节 C预处理,可能还需要一些时间,因为小编,昨天才下载了虚拟机 和 linux 系统,还没开始安

随机推荐