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寻址的方式,快速高效。

        

  • 相关阅读:
    c/c++设置图片为透明图
    转;说说AngularJS中的$parse和$eval
    转: css3: display:box详解
    转: 深入理解 AngularJS 的 Scope
    转:说说angularjs中的$parse和$eval
    转: 理解AngularJS中的依赖注入
    angularjs学习总结(快速预览版)
    XML基础知识
    读书笔记:js设计模式
    contains 和 ele.compareDocumentPosition确定html节点间的关系
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/9760603.html
Copyright © 2011-2022 走看看