| 如果是在Swift类的extension中定义的方法(重写OC基类的方法除外)。那么针对这个方法的调用总是会在编译时就决定,也就是说在调用这类对象方法时,方法调用指令中的函数地址将会以硬编码的形式存在。在extension中定义的方法无法在运行时做任何的替换和改变!而且方法函数的符号信息都不会保存到类的描述信息中去。这也就解释了在Swift中派生类无法重写一个基类中extension定义的方法的原因了。因为extension中的方法调用是硬编码完成,无法支持多态!下面的Swift源代码以及C伪代码实现说明了这个情况: ////////Swift源代码  //类定义 class CA {     open func foo(){} }  //类的extension定义 extension CA {    open func extfoo(){} }  func main() {   let obj = CA()   obj.foo()   obj.extfoo() }  ////////C伪代码  //...........................................运行时定义部分   //Swift类描述。 struct  swift_class {     ...   //其他的属性,因为这里不关心就不列出了。    //虚函数表刚好在结构体的第0x50的偏移位置。     IMP vtable[1]; };   //...........................................源代码中类的定义和方法的定义和实现部分   //类定义 struct CA {       struct  swift_class *isa; }  //类的方法函数的实现定义 void foo(){} //类的extension的方法函数实现定义 void extfoo(){}  //类的描述信息构建,这些都是在编译代码时就明确了并且保存在数据段中。 //extension中定义的函数不会保存到虚函数表中。 struct swift_class classCA; classCA.vtable[0] = {&foo};   //...........................................源代码中程序运行的部分  void main(){   CA *obj =  CA.__allocating_init(classCA)   obj->isa = &classCA;   asm("mov x20, obj");   //Swift中常规方法foo调用采用间接调用实现   obj->isa->vtable[0]();   //Swift中extension方法extfoo调用直接硬编码调用,而不是间接调用实现   extfoo(); } 
 需要注意的是extension中是可以重写OC基类的方法,但是不能重写Swift类中的定义的方法。具体原因根据上面的解释就非常清楚了。 类中定义的常规方法 如果是在Swift中定义的常规方法,方法的调用机制和C++中的虚函数的调用机制是非常相似的。Swift为每个类都建立了一个被称之为虚表的数组结构,这个数组会保存着类中所有定义的常规成员方法函数的地址。每个Swift类对象实例的内存布局中的第一个数据成员和OC对象相似,保存有一个类似isa的数据成员。isa中保存着Swift类的描述信息。对于Swift类的类描述结构苹果并未公开(也许有我并不知道),类的虚函数表保存在类描述结构的第0x50个字节的偏移处,每个虚表条目中保存着一个常规方法的函数地址指针。每一个对象方法调用的源代码在编译时就会转化为从虚表中取对应偏移位置的函数地址来实现间接的函数调用。下面是对于常规方法的调用Swift语言源代码和C语言伪代码实现: ////////Swift源代码  //基类定义 class CA {   open func foo1(_ a:Int){}   open func foo1(_ a:Int, _ b:Int){}   open func foo2(){} }  //扩展 extension CA{   open func extfoo(){}  }  //派生类定义 class CB:CA{   open func foo3(){}   override open func foo1(_ a:Int){} }  func testfunc(_ obj:CA){   obj.foo1(10) }  func main() {   let objA = A()   objA.foo1(10)   objA.foo1(10,20)   objA.foo2()   objA.extfoo()    let objB = B()   objB.foo1(10)   objB.foo1(10,20)   objB.foo2()   objB.foo3()   objB.extfoo()    testfunc(objA)   testfunc(objB) }  ////////C伪代码  //...........................................运行时定义部分  //Swift类描述。 struct swift_class {     ...   //其他的属性,因为这里不关心就不列出了     //虚函数表刚好在结构体的第0x50的偏移位置。     IMP vtable[0]; };   //...........................................源代码中类的定义和方法的定义和实现部分   //基类定义 struct CA {       struct swift_class *isa; };  //派生类定义 struct CB {    struct swift_class *isa; };  //基类CA的方法函数的实现,这里对所有方法名都进行修饰命名 void _$s3XXX2CAC4foo1yySiF(int a){}   //CA类中的foo1 void _$s3XXX2CAC4foo1yySi_SitF(int a, int b){} //CA类中的两个参数的foo1 void _$s3XXX2CAC4foo2yyF(){}   //CA类中的foo2 void _$s3XXX2CAC6extfooyyF(){} //CA类中的extfoo函数    //派生类CB的方法函数的实现。 void _$s3XXX2CBC4foo1yySiF(int a){}   //CB类中的foo1,重写了基类的方法,但是名字不一样了。 void _$s3XXX2CBC4foo3yyF(){}             //CB类中的foo3   //构造基类的描述信息以及虚函数表 struct swift_class classCA; classCA.vtable[3] = {&_$s3XXX2CAC4foo1yySiF, &_$s3XXX2CAC4foo1yySi_SitF, &_$s3XXX2CAC4foo2yyF};  //构造派生类的描述信息以及虚函数表,注意这里虚函数表会将基类的函数也添加进来而且排列在前面。 struct swift_class classCB; classCB.vtable[4] = {&_$s3XXX2CBC4foo1yySiF, &_$s3XXX2CAC4foo1yySi_SitF, &_$s3XXX2CAC4foo2yyF, &_$s3XXX2CBC4foo3yyF};  void testfunc(A *obj){    obj->isa->vtable[0](10);   //间接调用实现多态的能力。 }   //...........................................源代码中程序运行的部分  void main(){    CA *objA = CA.__allocating_init(classCA);    objA->isa = &classCA;    asm("mov x20, objA")    objA->isa->vtable[0](10);    objA->isa->vtable[1](10,20);    objA->isa->vtable[2]();    _$s3XXX2CAC6extfooyyF()    CB *objB = CB.__allocating_init(classCB);   objB->isa = &classCB;   asm("mov x20, objB");   objB->isa->vtable[0](10);   objB->isa->vtable[1](10,20);   objB->isa->vtable[2]();   objB->isa->vtable[3]();    _$s3XXX2CAC6extfooyyF();    testfunc(objA);   testfunc(objB);  } 
 从上面的代码中可以看出一些特点: (编辑:宣城站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |