swift封装
As far as papers go, I must confess this is a little long at some 2,000+ words. In the first half, I cover three basic access types: private, file private, and internal. In the second half, I cover creating a framework with public and open access types. Both sections are labeled and can be read independently.
就论文而言,我必须承认这有点长,大约有2,000多个单词。 在上半年中,我将介绍三种基本的访问类型:私有,文件私有和内部。 在第二部分中,我将介绍创建具有公共和开放访问类型的框架。 这两个部分均已标记,可以独立阅读。
Let’s start with some background. Back in the bygone days of the 1970s, the professor of Informatics at ETH Zurich, Switzerland, a man called Niklaus Wirth created and published what was then a revolutionary language for teaching. A language he called Pascal. It was a language based on his book Algorithms + Data Structures = Programs.
让我们从一些背景开始。 早在1970年代,瑞士苏黎世联邦理工学院的信息学教授叫尼克劳斯·沃思 ( Niklaus Wirth),他创造并出版了当时的革命性教学语言。 他称为Pascal的语言。 这是一种基于他的书“ 算法+数据结构=程序”的语言 。
It was one of the first high-level computer languages to introduce the concept of encapsulation. A concept we all take for granted today. The principle idea within it, the need to create a scope within which access to elements in your code could be restricted. The idea of private and public variables and methods.
它是最早引入封装概念的高级计算机语言之一。 我们今天都认为这是理所当然的概念。 其中的基本思想是创建一个范围的需求,该范围可以限制对代码中元素的访问。 私有和公共变量和方法的思想。
Indeed Pascal as a language was so well designed that Apple decided to use it to write Mac OS. Mac OS as in the OS in which the fated Lisa and Macintosh computers ran. A brave decision at a time when everybody else was still using C.
实际上,Pascal作为一种语言的设计是如此出色,以至于Apple决定使用它来编写Mac OS。 Mac OS,如运气好的Lisa和Macintosh计算机的OS。 在其他所有人仍在使用C的时候做出了一个勇敢的决定。
In the meantime, C itself was undergoing a transformation. Ten years after the launch of Pascal with the development of Objective C, again a language that adopted the ideas and concept of encapsulation. Coincidentally a language picked up again by Steve Jobs's new team on the NextStep OS project. The company that would give us Objective C.
同时,C本身正在接受转换。 Pascal推出十年后,随着Objective C的发展,该语言再次采用了封装的思想和概念。 碰巧的是,史蒂夫·乔布斯(Steve Jobs)的新团队在NextStep OS项目中再次采用了一种语言。 给我们目标C的公司
The rest is history, as they say. Jobs returned to Apple in 1997, bringing with him a new OS and a new language, Objective C. Objective C as you know, the precursor to Swift, which as we all know came out in 2014.
正如他们所说,其余就是历史。 乔布斯于1997年返回苹果,带来了一个新的操作系统和一种新的语言,即ObjectiveC。众所周知,Objective C是Swift的前身,众所周知,Swift在2014年问世。
Today, Swift has continued to build on Pascal’s legacy and has five levels of encapsulation in the language: private, fileprivate, internal, public, and open. Levels of access can applied to variables, classes, structs, enums, functions, methods, and even the new wrappers build-out of SwiftUI. Levels of access that are relative to the source file the entities and/or modules that said code is defined within.
如今,Swift继续在Pascal的遗产基础上继续发展,并在语言上具有五个封装级别:私有,文件私有,内部,公共和开放。 访问级别可以应用于变量,类,结构,枚举,函数,方法,甚至可以应用于SwiftUI的新包装。 相对于源文件的访问级别,在源文件中定义了所述代码的实体和/或模块。
私有,FilePrivate和内部 (Private, FilePrivate, and Internal)
Ok enough history, let’s code. We’re going to use two projects to illustrate how these levels of access work. We begin with the most restrictive, private. Create a new project using SwiftUI as the interface and add a cocoa touch class file to it, call it Person.class, and add the code you see here.
好的历史记录,让我们编码。 我们将使用两个项目来说明这些访问级别的工作方式。 我们从限制性最强的隐私开始。 使用SwiftUI作为界面创建一个新项目,并向其中添加可可触摸类文件,将其命名为Person.class,然后添加您在此处看到的代码。
class Person {
var id: String = "SecretID"
}
The SwiftUI interface access this object needs to look like this.
该对象的SwiftUI接口访问应如下所示。
The default access level here is internal. Internal means accessible across the entire module in which they are defined. By default, everything you create in an Xcode project has internal access. So having named the Person class within the SwiftUI implementation, all the variables within it are accessible to it. Now let’s try to lock things down a little. Change the id
in the person class to make it private.
此处的默认访问级别是内部。 内部方法可在定义它们的整个模块中访问。 默认情况下,您在Xcode项目中创建的所有内容都具有内部访问权限。 因此,在SwiftUI实现中命名了Person类后,即可访问其中的所有变量。 现在,让我们尝试锁定一些东西。 更改人员类别中的id
以使其私有。
private var id: String = "SecretID"
You will immediately get an error in your ContentView.swift SwiftUI code to warn you the class variables are no longer accessible. We’ve broken it, how to fix.
您将在ContentView.swift SwiftUI代码中立即收到错误消息,以警告您不再可以访问类变量。 我们已经破解了,如何解决。
Now let’s assume we don’t want to change the id
, we want to just read it. We can fix this error by defining a method within the class that we can use to return said id. Change the Person ID
class to look like the code shown here.
现在假设我们不想更改id
,我们只想读取它。 我们可以通过在类中定义一个可用来返回所述ID的方法来解决此错误。 更改Person ID
类,使其看起来像此处显示的代码。
class Person {
private var id: String = "SecretID"
func displayid() -> String {
return id
}
}
And well since the function displayed()
will be assigned internal permissions, we can call said function within our SwiftUI code.
而且由于函数display displayed()
将被分配内部权限,因此我们可以在SwiftUI代码中调用该函数。
struct ContentView: View {
@State var person = Person()
var body: some View {
Text("\(person.displayid())")
}
}
Moving forward imagine we need to be able to change the secret ID
. To do that we can create a new class (although in the same file as the Person.class
)to which will add a function shown here.
展望未来,我们需要能够更改secret ID
。 为此,我们可以创建一个新类(尽管与Person.class
在同一文件中),在该类中添加此处显示的功能。
class Management {
static func updateID(for person:Person, with newID:String ) {
person.id = newID
}
}
Of course, your new Management class won’t have access to the person.id
initially either, since it is a different class much like the SwiftUI struct. You will get the same error as you did before.
当然,新的Management类最初也将无法访问person.id
,因为它是一个与SwiftUI结构非常相似的类。 您将得到与以前相同的错误。
To fix this, but retain some security, we can change the access level of the id
variable in our Person class to fileprivate
. Since you defined the Management class in the same file as the Person class, it will gain access; without opening up access to the SwiftUI implementation in the ContentView.swift
file.
要解决此问题,但要保留一些安全性,我们可以将Person类中id
变量的访问级别更改为fileprivate
。 由于您在与Person类相同的文件中定义了Management类,因此它将获得访问权限; 而不在ContentView.swift
文件中打开对SwiftUI实现的访问。
fileprivate var id: String = "SecretID"
You can test the new implementation by changing the ContentView.swift
of your code to look like this.
您可以通过将代码的ContentView.swift
更改为如下所示来测试新的实现。
This will update the ID
you’ll see on the screen three seconds after it initially displays the secret ID
message. Note, I needed the dnr
variable here because without it SwiftUI will not know that it needs to re-run the main body again.
这将更新ID
,你会在屏幕三秒看到它最初显示后secret ID
消息。 注意,我在这里需要dnr
变量,因为没有它,SwiftUI不会知道它需要再次重新运行主体。
框架,公共和开放 (Frameworks, Public, and Open)
Now to illustrate the final two levels of encapsulation we’re going to switch projects. Go back to the desktop and create a new project. Call it BuyersPortal; I am going to use SwiftUI as an interface again.
现在,为了说明封装的最后两个级别,我们将切换项目。 返回桌面并创建一个新项目。 称为BuyersPortal; 我将再次使用SwiftUI作为接口。
Open the ContentView.swift
and add these structures and classes to it.
打开ContentView.swift
并向其中添加这些结构和类。
What we define here is a Product record and a class that will use it. Now update the ContentView.swift
to access your new struct/classes.
我们在此处定义的是产品记录和将使用它的类。 现在更新ContentView.swift
以访问您的新结构/类。
When you’re ready to run; go for it. It’ll display the newCustomer
with a value of zero. Click on the text and it’ll access the method you just defined and the price will change. The default permissions on the Product
and Purchases
classes are internal and with everything in the same file, it’ll all work perfectly.
当您准备好跑步时; 去吧。 它将显示值为零的newCustomer
。 单击文本,它将访问您刚定义的方法,价格将发生变化。 Product
和Purchases
类的默认权限是内部权限,并且所有内容都在同一文件中,因此可以完美运行。
Now imagine you’re working with your peer, Stewart, remotely. Your part of the job is to define Product
and Purchases
objects and his part is to put it in action. Now you could write the code as you see here and ship the source, but it isn’t very practical and maybe you want to retain more control over it.
现在,假设您正在与同行Stewart远程合作。 您的工作部分是定义“ Product
和Purchases
对象,而他的部分是将其付诸实践。 现在,您可以按此处所见的方式编写代码并发送源代码,但这不是很实用,也许您想保留对其的更多控制权。
This is where frameworks, public, and open access controls come into the picture. You embed the Product
and Purchases
objects into a framework with public/open permissions. A framework you ship to Stewart confident that he’ll be able to use it, but not abuse it.
这是框架,公共和开放访问控制出现的地方。 您将“ Product
和“ Purchases
对象嵌入具有公共/开放权限的框架中。 您提供给Stewart的框架充满信心,他可以使用它,但不会滥用它。
To build a framework go back to Xcode and start a new project. Call it Engine
, but wait, don’t choose the usual single page app, choose a framework this time.
要构建框架,请回到Xcode并开始一个新项目。 称它为Engine
,但是等等,不要选择通常的单页应用程序,这次选择一个框架。
![Image for post](https://miro.medium.com/max/9999/1*LLTygysr-ZznMdMfl7QiuA.png)
A project will come up that will look rather bare with just a few files within it. Add a new swift source code file to it and copy and paste the code I outlined above defining the Product
and Purchase
objects & methods in your new framework project.
即将出现一个项目,其中仅包含几个文件就显得很裸露。 向其中添加一个新的快速源代码文件,然后将上面概述的代码复制并粘贴到新框架项目中,这些代码定义了Product
和Purchase
对象和方法。
Compile it and check that you haven’t made any typos and don’t have any errors. Close the project and now follow these steps carefully.
编译它,并检查您没有打错任何文字并且没有任何错误。 关闭该项目,然后现在仔细执行以下步骤。
Go back to the
BuyersPortal
project, the one with the code you just cut and pasted your struct and class out of, and comment everything out.返回到
BuyersPortal
项目,该项目带有刚刚剪切并粘贴结构和类的代码,并注释掉了所有内容。Open the folder containing the
Engine
project (the one with the struct and class within in) and then drag thexcodeproj
within it to theBuyersPortal
.打开包含
Engine
项目的文件夹(其中包含struct和class的文件夹),然后将其中的xcodeproj
拖到BuyersPortal
。
The file inspector of the BuyersPortal
project should now look like this. The Engine
project is within the BuyersPortal
project.
现在, BuyersPortal
项目的文件检查器应如下所示。 Engine
项目在BuyersPortal
项目中。
![Image for post](https://miro.medium.com/max/9999/1*Bm3qT8xKyNJTT-3a-vesrw.png)
Strictly speaking, we didn’t need to include the whole Engine
project here, we could just include the framework. But it makes more sense to include the whole project on this occasion since we’re going to be changing the code within it to get our permissions correct before we ship the framework to our man Stewart.
严格来说,我们不需要在这里包含整个Engine
项目,我们可以仅包含框架。 但是在这种情况下包含整个项目更有意义,因为在将框架交付给我们的人Stewart之前,我们将更改其中的代码以获取正确的权限。
Now, compile everything to make sure we haven’t managed to corrupt our desktop. Ok, we’re ready to slowly rebuild the ContentView.swif
t in the BuyersPortal
. Start with the line to define Purchases
. It won’t work; you’ll get an error “Cannot find…”
现在,编译所有内容以确保我们没有破坏桌面。 好的,我们已经准备好在BuyersPortal
缓慢重建ContentView.swif
t了。 从定义“ Purchases
的行开始。 它行不通; 您将收到错误消息“找不到...”
This isn’t a permission problem in swift, it is telling you it doesn’t know what you are talking about. It still an Xcode problem.
这不是快速的权限问题,它告诉您它不知道您在说什么。 它仍然是一个Xcode问题。
We need to do one more step to integrate our Engine
project into the BuyersPortal
. Go back to the project and expand the Engine
project, look under products, you want the Engine.framework
.
我们需要再做一步,将我们的Engine
项目集成到BuyersPortal
。 返回该项目并展开Engine
项目,在产品下面查找您想要的Engine.framework
。
Now select the BuyersPortal
project and scroll down to the down to the Frameworks, Libraries, and Embedded Content area. You need to drag the Engine.framework
you just found into this section. The BuyersPortal
project Frameworks, Libraries, and Embedded Content should look like this if you get things correct.
现在选择BuyersPortal
项目,然后向下滚动到Frameworks,Libraries和Embedded Content区域。 您需要将刚发现的Engine.framework
拖到本部分中。 如果您正确无误,那么BuyersPortal
项目的框架,库和嵌入式内容应如下所示。
![Image for post](https://miro.medium.com/max/9999/1*-76EJQrIwmDzBsv9ToAl9A.png)
Don’t make the mistake of dragging down to the Frameworks, Libraries, and Embedded code section of the Engine
project, that won’t work!
不要误将其拖到Engine
项目的Frameworks,Libraries和Embedded code部分,这是行不通的!
Having linked it in, make sure you now include it with an import statement in your ContentView.swift
file too. The ContentView.swift
in the BuyersPortal
that is.
链接完之后,请确保现在也将它与导入语句一起包含在ContentView.swift
文件中。 在BuyersPortal
中的ContentView.swift
。
import Engine
Now uncomment the initial lines to define your first Purchases
object.
现在取消注释初始行以定义您的第一个Purchases
对象。
@State var newCustomer = Purchases()
It won’t work, but don’t worry, we’re almost there. Now you need to fix the Swift permissions.
这行不通,但是不用担心,我们快到了。 现在,您需要修复Swift权限。
At this point, all the permissions in the Engine
class are set to the default ones, namely internal. Change the permission on the Purchases
class to public and try again. The error message will change, it will now complain about the initializer not being public. Add an initializer to your Purchases
class and compile it again. This time it’ll work. We’re making progress.
此时, Engine
类中的所有权限都设置为默认权限,即内部权限。 将“ Purchases
类的权限更改为“公开”,然后重试。 错误消息将更改,现在将抱怨初始化程序未公开。 在您的Purchases
类中添加一个初始化器,然后再次编译它。 这次它将起作用。 我们正在进步。
Uncomment the onTapGesture
to the Text
object, it will complain again about the access rights on the Product
struct and the products
variable within the Purchases
class, as well as access to the calculatePrice
method. Make them all public in your Engine
class. Your code in the Engine
product should end up looking like this.
取消将onTapGesture
注释为Text
对象,它将再次抱怨对Product
结构和Purchases
类中的products
变量的访问权限,以及对calculatePrice
方法的访问。 将它们全部公开在您的Engine
类中。 您在Engine
产品中的代码应最终看起来像这样。
Compile and run. Tap on the newCustomer
field and it should run the calculate price
method and report a new price. And well, there you have it, public access.
编译并运行。 点击newCustomer
字段,它将运行calculate price
方法并报告新价格。 而且,您可以使用它,公共访问。
We covered all but the last type of access control, namely, open. Now imagine for a moment Stewart wants to subclass our Purchases
class here. He might, for example, want a discount class. A class that inherits its values and methods directly from our Purchases
class.
我们介绍了除最后一种访问控制(即开放)以外的所有内容。 现在想象一下,斯图尔特想在这里将我们的Purchases
类归类。 例如,他可能想要折扣课程。 直接从我们的Purchases
类继承其值和方法的类。
Edit the BuyersPortal
project and add a new file to it, a DiscountPurchases.swift
. Within the DiscountPurchases.swift
file add this code. Stewart would like to offer discounts to buyers who are older than 55.
编辑BuyersPortal
项目并向其中添加一个新文件DiscountPurchases.swift
。 在DiscountPurchases.swift
文件中,添加此代码。 斯图尔特想为55岁以上的买家提供折扣。
To be clear, this won’t work yet. We need to tweak the permissions on our Engine
class again.
需要明确的是,这还行不通。 我们需要再次调整Engine
类的权限。
If he tried it as is, it will return another access control error. This isn’t what we want or what he needs. Change the code to look like this. You need to make the purchases
class an open one. Change the public access on the function calculatePrice
too, since he will also need access to this.
如果他按原样尝试,它将返回另一个访问控制错误。 这不是我们想要的,也不是他的需要。 更改代码看起来像这样。 您需要将purchases
课程设为公开课程。 还要更改函数calculatePrice
上的公共访问权限,因为他也将需要访问此权限。
open class Purchases {
Now go back again to the DiscountPurchases
class and add this code.
现在,再次返回DiscountPurchases
类,并添加此代码。
override func calculatePrice() -> Double {
super.calculatePrice() * (1 - discountPercentage / 100)
}
Everything should now compile. All you need to do is add some code into the SwiftUI field to bring it all together. To test your new framework that you’ll be shipping out, use this code.
现在一切都应该编译了。 您需要做的就是将一些代码添加到SwiftUI字段中,以将它们整合在一起。 要测试将要交付的新框架,请使用此代码。
Which brings me to the end. We’ve covered all the major access types in these two projects. Before I go, however, I want to point you in the direction of a video on which much of this paper is based. A video put together by, you guessed it, my peer Stewart. An excellent resource that covers the same material you’ll find here, going into a little more detail. You can find the video here.
这使我走到了尽头。 我们已经涵盖了这两个项目中的所有主要访问类型。 但是,在开始之前,我想向您介绍视频,该视频是本文的大部分内容。 您猜对了,我的同伴Stewart录制的视频。 一个很好的资源,涵盖了您将在此处找到的相同材料,并进行了更详细的介绍。 您可以在此处找到视频。
swift封装