zoukankan      html  css  js  c++  java
  • SwiftObject 杂记

    一、前言

      看了一段时间的Swift,慢慢转变了一些对Swift的看法。

      Swift作为苹果新晋的开发语言、具有模板编程、函数编程、协议多继承、vTable静态绑定、值引用类型区分、Option类型等动态语法的多种特性。

      Swift作为一门跨平台的语言,非常强调性能,静态绑定是Swift跟OC语言的动态派发迥异的区别。Objetive-C中的Runtime优秀的设计让OC这门语言有着优秀的动态特性,

        Swift的语言设计中一部分为了和OC桥接,一部分也参考了OC的设计让Swift具有一些动态特性,比如自省。

      Swift强调安全,Optional代替OC中的空指针,同时优化了性能。Optional调用链遇到中间的Optional不会继续执行。同时值类型的语义的大量使用可以规避线程安全带来的问题。

    二、本次文章主要探究Swift编译运行机制

      1)编写一个控制台程序,将可执行文件拖入Hopper进行反编译

      注:下一部分代码借鉴 https://mp.weixin.qq.com/s/zIkB9KnAt1YPWGOOwyqY3Q 《Swift 对象内存模型探究(一)》

    //
    //  main.swift
    //  TestSwift2
    //
    //  Created by lunli on 2018/10/9.
    //  Copyright © 2018年 lunli. All rights reserved.
    //
    
    import Foundation
    import ObjectiveC
    
    class People{
        var xxxxx = 1
    }
    
    class Driver:People{
        var yyyyy = 2
    }
    
    class SellerPeople{
        var zzzzz = 3
    }
    
    struct Person {
        var name: String
        var age: Int
    }
    
    class ViewController {
        var x = 123456
        var person: Person? {
            didSet{
                
                print("Called after setting the new value")
                if let name = person?.name {
                    print("New name is (name) and old name is (String(describing: oldValue?.name))")
                }
            }
            willSet(myNewValue) {
                
                print("Called before setting the new value")
                if let newName = myNewValue?.name {
                    print("New name is (newName)")
                }
            }
        }
    
    }
    
    var p = Driver()
    print(type(of: p))
    print(String.init(format: "%s", object_getClassName(p)))
    
    var v = ViewController()
    v.person = Person(name: "1234", age: 123)
    
    class Human : ViewController {
        var age: Int?
        var name: String?
        var nicknames: [String] = [String]()
        
        //返回指向 Human 实例头部的指针
        func headPointerOfClass() -> UnsafeMutablePointer<Int8> {
            let opaquePointer = Unmanaged.passUnretained(self as AnyObject).toOpaque()
            let mutableTypedPointer = opaquePointer.bindMemory(to: Int8.self, capacity: MemoryLayout<Human>.stride)
            return UnsafeMutablePointer<Int8>(mutableTypedPointer)
        }
    }
    
    let human = Human()
    let arrFormJson = ["goudan","zhaosi", "wangwu"]
    
    //拿到指向 human 堆内存的 void * 指针
    let humanRawPtr = UnsafeMutableRawPointer(human.headPointerOfClass())
    
    //nicknames 数组在内存中偏移 64byte 的位置(16 + 16 + 32)
    let humanNickNamesPtr =  humanRawPtr.advanced(by: 64).assumingMemoryBound(to: Array<String>.self)
    //human.nicknames
    //[]
    let test = humanRawPtr.advanced(by: 0).assumingMemoryBound(to: AnyObject.self)
    let test2 = humanRawPtr.advanced(by: 8).assumingMemoryBound(to: Int64.self)
    print(test)
    
    humanNickNamesPtr.initialize(to: arrFormJson)
    print(human.nicknames)          //["goudan","zhaosi", "wangwu"]
    
    
    
    print((human as AnyObject).isKind(of: ViewController.self))
    

      拖入Hopper之后,可以看到

      我们可以清晰看到SellerPeople的类的定义,和其MetaClass的定义;其定义跟现有的OC Class类型定义比较类似,一个指针指向父类,一个指向元类,Cache未知、一个vtable表示方法调用列表、data表示类中的变量数据

      上面的截图可以看到SellerPeople中ivar的定义和名字方法的定义、通过这些信息可以完全实现一个对象类型的检测、属性列表、方法列表等。

    在DEBUG模式生成的可执行文件下面,我们用命令行对其中的符号进行恢复,可以清晰看到类名、变量名。

    LUNLI-MC1:Swift 二进制分析 lunli$ nm TestSwift2|xcrun swift-demangle|grep "ViewController"
    0000000100002120 t TestSwift2.ViewController.person.didset : TestSwift2.Person?
    0000000100002ae0 T TestSwift2.ViewController.person.getter : TestSwift2.Person?
    0000000100002d70 T TestSwift2.ViewController.person.materializeForSet : TestSwift2.Person?
    0000000100002d40 t closure #1 : () in TestSwift2.ViewController.person.materializeForSet : TestSwift2.Person?
    00000001004f3cd8 S direct field offset for TestSwift2.ViewController.person : TestSwift2.Person?
    0000000100002110 T variable initialization expression of TestSwift2.ViewController.person : TestSwift2.Person?
    0000000100002b60 T TestSwift2.ViewController.person.setter : TestSwift2.Person?
    00000001000026f0 t TestSwift2.ViewController.person.willset : TestSwift2.Person?
    0000000100002e10 T TestSwift2.ViewController.__allocating_init() -> TestSwift2.ViewController
    0000000100002f60 T TestSwift2.ViewController.init() -> TestSwift2.ViewController
    0000000100511110 s reflection metadata field descriptor TestSwift2.ViewController
    0000000100589e38 b lazy cache variable for type metadata for TestSwift2.ViewController
    0000000100001cd0 T type metadata accessor for TestSwift2.ViewController
    0000000100584d60 d full type metadata for TestSwift2.ViewController
    0000000100584d38 D metaclass for TestSwift2.ViewController
    00000001004f3cf0 S nominal type descriptor for TestSwift2.ViewController
    0000000100584d70 D type metadata for TestSwift2.ViewController
    0000000100003030 T TestSwift2.ViewController.__deallocating_deinit
    0000000100002fd0 T TestSwift2.ViewController.deinit
    0000000100589ad8 S TestSwift2.v : TestSwift2.ViewController
    0000000100507a0e s _symbolic ____ 10TestSwift214ViewControllerC
    

      

      2)既然能看到任意swift定义的class结构,那么 swift是否存在一个共同的父类结构?

      搜索之后看到一个答案:

      

        原文:https://stackoverflow.com/questions/24137368/why-is-there-no-universal-base-class-in-swift

      我写了一点代码来模拟这个特性,一段OC和Swift混编的代码

      

    import Foundation
    
    class People{
        var xxxxx = 1
    }
    
    class Driver:People{
        var yyyyy = 2
    }
    
    class SellerPeople{
        var zzzzz = 3
    }
    
    struct Person {
        var name: String
        var age: Int
    }
    
    class ViewController1 : NSObject {
        
        var obj = SellerPeople()
        @objc var str = "Hello World"
        var x = 123456
        var person: Person? {
            didSet{
                
                print("Called after setting the new value")
                if let name = person?.name {
                    print("New name is (name) and old name is (String(describing: oldValue?.name))")
                }
            }
            willSet(myNewValue) {
                
                print("Called before setting the new value")
                if let newName = myNewValue?.name {
                    print("New name is (newName)")
                }
            }
        }
        
        @objc func getSwiftObj() -> AnyObject {
            return obj
        }
        
    }
    
    class Human : ViewController1 {
        var age: Int?
        var name: String?
        var nicknames: [String] = [String]()
        
        //返回指向 Human 实例头部的指针
        func headPointerOfClass() -> UnsafeMutablePointer<Int8> {
            let opaquePointer = Unmanaged.passUnretained(self as AnyObject).toOpaque()
            let mutableTypedPointer = opaquePointer.bindMemory(to: Int8.self, capacity: MemoryLayout<Human>.stride)
            return UnsafeMutablePointer<Int8>(mutableTypedPointer)
        }
    }
    

        注意getSwiftObject方法返回的是一个Swift对象,我们将这个对象拿到OC中用调试器进行调试

    可以看到调试器中打印出来,一个纯Swift没有指定父类的类默认继承的对象是SwiftObject,参考这个类的实现如下

    https://github.com/apple/swift/blob/f4db1dd7a4abba2685247e1a7415d4fcb91f640d/stdlib/public/runtime/SwiftObject.h 

    //===--- SwiftObject.h - Native Swift Object root class ---------*- C++ -*-===//
    //
    // This source file is part of the Swift.org open source project
    //
    // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
    // Licensed under Apache License v2.0 with Runtime Library Exception
    //
    // See https://swift.org/LICENSE.txt for license information
    // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
    //
    //===----------------------------------------------------------------------===//
    //
    // This implements the Objective-C root class that provides basic `id`-
    // compatibility and `NSObject` protocol conformance for pure Swift classes.
    //
    //===----------------------------------------------------------------------===//
    
    #ifndef SWIFT_RUNTIME_SWIFTOBJECT_H
    #define SWIFT_RUNTIME_SWIFTOBJECT_H
    
    #include "swift/Runtime/Config.h"
    #include <cstdint>
    #include <utility>
    #include "swift/Runtime/HeapObject.h"
    #if SWIFT_OBJC_INTEROP
    #include "llvm/Support/Compiler.h"
    #include <objc/NSObject.h>
    #endif
    
    
    #if SWIFT_OBJC_INTEROP
    
    #if SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
    // Source code: "SwiftObject"
    // Real class name: mangled "Swift._SwiftObject"
    #define SwiftObject _TtCs12_SwiftObject
    #else
    // Pre-stable ABI uses un-mangled name for SwiftObject
    #endif
    
    #if __has_attribute(objc_root_class)
    __attribute__((__objc_root_class__))
    #endif
    SWIFT_RUNTIME_EXPORT @interface SwiftObject<NSObject> {
     @private
      Class isa;
      SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
    }
    
    - (BOOL)isEqual:(id)object;
    - (NSUInteger)hash;
    
    - (Class)superclass;
    - (Class)class;
    - (instancetype)self;
    - (struct _NSZone *)zone;
    
    - (id)performSelector:(SEL)aSelector;
    - (id)performSelector:(SEL)aSelector withObject:(id)object;
    - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
    
    - (BOOL)isProxy;
    
    + (BOOL)isSubclassOfClass:(Class)aClass;
    - (BOOL)isKindOfClass:(Class)aClass;
    - (BOOL)isMemberOfClass:(Class)aClass;
    - (BOOL)conformsToProtocol:(Protocol *)aProtocol;
    
    - (BOOL)respondsToSelector:(SEL)aSelector;
    + (BOOL)instancesRespondToSelector:(SEL)aSelector;
    - (IMP)methodForSelector:(SEL)aSelector;
    + (IMP)instanceMethodForSelector:(SEL)aSelector;
    
    - (instancetype)retain;
    - (oneway void)release;
    - (instancetype)autorelease;
    - (NSUInteger)retainCount;
    
    - (NSString *)description;
    - (NSString *)debugDescription;
    @end
    
    namespace swift {
    
    NSString *getDescription(OpaqueValue *value, const Metadata *type);
    
    }
    
    #endif
    
    #endif
    

      这个类包含一个实例变量isa,这个Class是一个指针,指向的是OC Runtime中类定义的结构;同时这个类实现了NSObject的协议,猜测这样的设计是为了跟OC进行桥接。

    3)Swift的对象的内存布局

      这里的内容主要来自第一篇提到的文章,一个Swift引用指向的内存区域,

        第一个指针应该是isa,

        第二个8字节(32位机器为4字节)为引用计数,

        第三块区域是vtable指针,

        接下来的是继承的变量

        接下来是这个类实现的变量

      可见这里的对象内存布局和C++有些类似,但是增加了一个isa的东西,让这个对象具有了一些动态特征。方法执行采用vtable寻址的方式,快速高效。

        

  • 相关阅读:
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/9760603.html
Copyright © 2011-2022 走看看