swift 引用swift_方法混乱 Swift

swift 引用swift

第一件事 (First things first)

Before the explanation about Method Swizzling, it’s important to understand what is the Swift Runtime, once it’s a key concept that enables language features like the Swizlling.

在解释方法旋转之前,重要的是要了解什么是Swift Runtime,一旦它成为启用诸如Swizlling之类的语言功能的关键概念。

运行 (Runtime)

The Swift Runtime is a part of the standard library that enables behaviors while the application is running. Good examples of Those behaviors are casts, reflections, and memory allocation.

Swift Runtime是标准库的一部分,可在应用程序运行时启用行为。 这些行为的好例子是强制转换,反射和内存分配。

At this moment developers start to realize that those behaviors are pretty common in the development. Casts, for example, are present almost every time inheritance is used, transforming superclasses into subclasses.

此时,开发人员开始意识到这些行为在开发中非常普遍。 例如,强制转换几乎在每次使用继承时都存在,从而将超类转换为子类。

但是这些东西是运行时功能如何? (But how those things are Runtime features?)

All the examples given are very common, for example, a cast, that is basically the keyword as in the code. But this is what a cast represents only in the compiling time, which leads to the next important concept.

给出的所有实施例中是很常见的,例如,流延,也就是基本上与关键字as在代码。 但这只是强制转换在编译时所代表的意思,这导致了下一个重要概念。

运行时X编译时间 (Runtime X Compile time)

In development, in almost all languages, the concept of those moments is very important in an application

在开发中,几乎所有语言都用这些时刻的概念在应用程序中非常重要

The Compile time is the moment where the code is written and compiled, which means is the time where the code is verified to check if it’s following the lexical, syntax and semantic rules of the language.

编译时间是编写和编译代码的时刻,这意味着验证代码以检查其是否遵循该语言的词汇,语法和语义规则。

The Runtime happens after the compiling time when the code is running, which means the code is right in terms of language rules and we can interact with it given inputs for example. Besides the interaction possibility, during the runtime, the application also deals with a lot of responsibilities, like allocate memory to variables, structs, classes, and so on.

运行时发生在代码运行的编译时间之后,这意味着代码在语言规则方面是正确的,例如,我们可以在给定输入的情况下与其进行交互。 除了可能的交互作用之外,在运行时,应用程序还处理很多责任,例如将内存分配给变量,结构,类等。

内存分配 (Memory allocation)

As said previously, one of the responsibilities of Runtime is Memory allocation, that is the process to separate parts of the device memory so that it is possible to save information, like a class and its properties values and methods. A good way to understand this is by looking at how it is done by the application, which can be represented by a memory table.The following example shows a memory table of a class named SomeClass, this class has a property named value of type Int and a method named foo.

如前所述,运行时的职责之一是内存分配,即分配设备内存部分的过程,以便可以保存信息,例如类及其属性值和方法。 了解这一点的一种好方法是查看应用程序是如何完成的,可以通过内存表来表示。下面的示例显示了一个名为SomeClass的类的内存表,该类具有名为value的属性Int类型还有一个名为foo的方法。

Image for post
SomeClass Memory Table example
SomeClass内存表示例

A Memory table usually has two columns, the first representing the memory address, and the second one the value that is saved in this address.In this example the property value is in the address #110 and has saved the Int value 5000. To represent a method, there is the address #111 that has the value #230, which is an address and that address has the value 100, that can be assumed as the foo implementation.

内存表通常有两列,第一列代表内存地址,第二列代表保存在该地址中的value在此示例中,属性value位于地址#110并保存了Int5000 。 为了表示一种方法,存在一个具有值#230的地址#111 ,该地址是一个地址,并且该地址具有值100 ,可以假定为foo实现。

The address #111 can be called Pointer. A pointer is a really important concept in languages like Swift, which is a C based language. A pointer is an address that holds another address and so on. As addresses values are mutable during runtime, a pointer can point to different addresses, with different values.

地址#111可以称为Pointer 在像Swift这样的基于C语言的语言中,指针是一个非常重要的概念。 指针是保存另一个地址的地址,依此类推。 由于地址值在运行时期间是可变的,因此指针可以指向具有不同值的不同地址。

Swift中的内存分配-更深入 (Memory allocation in Swift — Going deeper)

In Swift, during the compile time, the Swift compiler makes it easier to — during Runtime — allocate memory to new instances of some classes.

在Swift中,在编译时,Swift编译器使运行时更容易为某些类的新实例分配内存。

To do this, the compiler creates a Dispatch Table, this table is created when an object is loaded in memory, which is different from instantiating an object.

为此,编译器创建一个Dispatch Table ,该表是在将对象加载到内存中时创建的,这与实例化对象不同。

  • Load: An object is loaded in the first time it’s created. It’s important to notice that it only happens once and only to objects exposed to the Objective-C compiler (it’s possible by making the class inherit from NSObject) since the greater power of Runtime comes from it.

    加载:对象在首次创建时被加载。 重要的是要注意,它仅一次且仅对暴露给Objective-C编译器的对象发生(可以通过使类继承自NSObject ),因为运行时的强大之处在于它。

  • Instantiate: Every time an object is created it’s also instantiated, which means, a new part of the device memory will be separated to save this object. If the object is exposed to the Obj-C to separate the memory, it will use a Dispatch Table, as like a template, to know how much of memory will be separated and what values, it will save.

    实例化:每次创建对象时都会对其进行实例化,这意味着设备内存的新部分将被分离以保存该对象。 如果对象暴露在Obj-C中以分离内存,则它将像模板一样使用Dispatch Table(调度表)来知道将分离多少内存以及将保存哪些值。

Apple’s documentation explains how it works with the methods +load and +initialize.

Apple的文档说明了如何使用+load+initialize

调度表 (Dispatch Table)

The Dispatch Table is created to help the application instantiate new instances during Runtime in a faster way. The following example is a dispatch table from a class named SomeClass

创建调度表是为了帮助应用程序在运行时以更快的方式实例化新实例。 以下示例是名为SomeClass的类的调度表

Image for post
SomeClass Dispatch Table example
SomeClass调度表示例

This table represents a class by its Methods. A Method is a C struct with the properties Selector and Implementation.

该表通过其Methods表示一个类。 Method是具有属性SelectorImplementationC struct

The Selector is a C string that represents the method name, for example, if a class named SomeClass has a method named foofunc foo() — its selector will be "SomeClass.foo".

所述Selector是一个C string ,它表示方法名,例如,如果一个已命名的类SomeClass具有method命名为foo - func foo() -其选择器将是"SomeClass.foo"

The Implementation is a pointer to the code instructions that the method executes when called.

Implementation是指向该方法在调用时执行的代码指令的指针。

方法混乱 (Method Swizzling)

After all the previous concepts, understand the Method Swizzling is easy.

在了解了所有先前的概念之后,便很容易了解方法混乱。

Method Swizzling is a feature enabled by the Runtime that changes the behavior of every single instance of some class without the use of inheritance or extension. It basically switches two methods implementations.

方法Swizzling是运行时启用的一项功能,可在不使用继承或扩展的情况下更改某个类的每个单个实例的行为。 它基本上切换了两种方法的实现。

This change is possible in Swift because of the Dispatch Table and the Pointers. The next example shows what a swizzle does in the dispatch table to enable this change of behavior in Runtime.

由于调度表指针,在Swift中可以进行此更改 下一个示例显示了swizzle在调度表中执行的操作,以在运行系统中启用此行为更改。

Image for post
SomeClass Swizzle example
SomeClass Swizzle示例

The example shows a Swizzle between "SomeOtherMethod" e "SomeNMethod" which means an exchange between the implementations pointer #220 and #300. This is possible because a pointer can change where it is pointing during Runtime.

该示例示出之间的拌和 "SomeOtherMethod" é "SomeNMethod" ,这意味着该实施方式之间的交换指针#220#300 。 这是可能的,因为在运行时指针可以更改其指向的位置。

(Code)

Although the concept looks easy after the explanation the code can be a little scary but is just because it follows the C functions name pattern.

尽管在解释之后这个概念看起来很简单,但是代码可能有点吓人,但这仅仅是因为它遵循C函数名称模式。

To make a Swizzle it’s necessary to access the dispatch table properties and exchange the IMP of two methods.

要创建Swizzle,必须访问调度表属性并交换两种方法的IMP

First, it’s necessary to find in which table the swizzle will happen, in other words, which class will have the behavior exchanged. There are some ways to find it, in the snippet below are some o them.

首先,有必要查找在哪个表中发生混乱,换句话说,哪个类将交换行为。 有一些找到它的方法,下面的代码片段中有一些。

Second, it’s necessary to know which methods will exchange their implementations. The best way to find a Method is through its name, that is the Selector.

其次,有必要知道哪些方法将交换其实现。 查找Method的最佳Method是通过其名称,即Selector

It’s possible to get the Selector by its name. The following examples show how to do it.

可以通过其名称获取Selector 。 以下示例显示了如何执行此操作。

With the class type and the method selector — that represents the dispatch table and one value in column SEL respectively —it’s possible to get the Method, which is the full line in the table.

使用类类型和方法选择器(分别表示调度表和SEL列中的一个值),可以获取Method ,即表中的完整行。

To get the Method use the function class_getInstanceMethod.

要获取Method使用函数class_getInstanceMethod

Since the Swizzling is an exchange, all this process must happen twice.

由于Swizzling是一种交换,因此所有此过程必须进行两次。

With all this information from the dispatch table, it’s possible to make the swizzle.

有了调度表中的所有这些信息,就有可能引起麻烦。

It’s possible to encapsulate the swizzle in a static function as following.

可以如下将静态包封装到静态函数中。

With this is possible to change every instance — of any class that inherits from NSObject— implementation between two methods.

这样就可以在两个方法之间更改每个实例(从NSObject继承的任何类的实例)的实现。

何时使用方法筛选 (When to use a Method Swizzle)

With the theory and the code, the only thing left is to know where to use this technique.

有了理论和代码,剩下的唯一一件事就是知道在哪里使用这种技术。

As the Swizzling changes every instance implementation it’s a global change, so its use should take it into account. So it’s recommended to use the swizzle when all instances of some class should do something and inheritance is not an option, or when it must change a class behavior in an extension, but the function can’t be overridden.

当Swizzling更改每个实例实现时,它是一个全局更改,因此应将其使用考虑在内。 因此,当某个类的所有实例都应执行某项操作且继承不是一个选项时,或者当它必须更改扩展中的类行为但不能覆盖该函数时,建议使用swizzle。

To see a real example take a look in the below Playground.

要查看真实示例,请在下面的Playground中查看。

After running the playground it’s possible to notice that the Swizzle is an important feature and very powerful, but as uncle Ben said.

在跑完操场后,您可能会注意到Swizzle是一项重要功能,功能非常强大,但正如Ben叔叔所说的那样。

“With great power comes great responsibility”

“拥有权利的同时也被赋予了重大的责任”

Although this feature of Runtime can enable a lot of possibilities it can cause problems too, like bug tracking, once it will change the behavior of the application during runtime, and in big projects, it can be a nightmare to control, since it will affect all the project.

尽管运行时的此功能可以带来很多可能性,但它也可能引起问题,例如错误跟踪,一旦它会在运行时更改应用程序的行为,并且在大型项目中,它将成为噩梦般的控制,因为它将影响所有项目。

翻译自: https://medium.com/a-swift-journey/method-swizzling-swift-2f281aae189b

swift 引用swift

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值