objective c - AnyClass is NSObjectProtocol... sometimes? -


following on this question got curious described behavior , did investigation left me quite puzzled.

the problem

checking nsobjectprotocol return of nsclassfromstring returns true in case except return of nsclassfromstring("wknsurlrequest"). fact results true bit surprising me pureclass , swiftobject.

import uikit import webkit import objectivec  class sigh: nsobject { } class pureclass { }  let sighclass = nsclassfromstring(nsstringfromclass(sigh.self))! let pureclass = nsclassfromstring(nsstringfromclass(pureclass.self))! let nsobject = nsclassfromstring("nsobject")! let wkrequestclass = nsclassfromstring("wknsurlrequest")! let swiftobject = nsclassfromstring("swiftobject")!  print("\n*nsobjectprotocol conformance*") print("nsobject: ", nsobject nsobjectprotocol) //print("wkrequestclass: ", wkrequestclass nsobjectprotocol) print("wkrequestclass: crash") print("sighclass: ", sighclass nsobjectprotocol) print("pureclass: ", pureclass nsobjectprotocol) print("swiftobject: ", swiftobject nsobjectprotocol) 

we checking not instance of classes, return of nsclassfromstring anyclass?.

anyclass typedef anyobject.type. why nsobjectprotocol? why not wkrequestclass?

what mecki said true , can check reading webkit source code: wknsurlrequest inherits wkobject root class conforming nsobjectprotocol, because wkobject conforms wkobject(protocol) extends nsobject(protocol).

@protocol wkobject <nsobject>  @property (readonly) api::object& _apiobject;  @end  ns_root_class @interface wkobject <wkobject>  - (nsobject *)_web_createtarget ns_returns_retained;  @end 

source: https://github.com/webkit/webkit/blob/master/source/webkit2/shared/cocoa/wkobject.h

mecki best guess kind of crash runtime error tried explain somehow. here playground:

//: playground - noun: place people can play  import uikit import webkit import objectivec  class sigh: nsobject { } class pureclass { }  let sighclass: anyclass = nsclassfromstring(nsstringfromclass(sigh.self))! let pureclass: anyclass = nsclassfromstring(nsstringfromclass(pureclass.self))! let nsobject: anyclass = nsclassfromstring("nsobject")! let wkrequestclass: anyclass = nsclassfromstring("wknsurlrequest")! let swiftobject: anyclass = nsclassfromstring("swiftobject")!  print("\n*nsobjectprotocol conformance*") print("nsobject: ", nsobject nsobjectprotocol) //print("wkrequestclass: ", wkrequestclass nsobjectprotocol) print("wkrequestclass: crash") print("sighclass: ", sighclass nsobjectprotocol) print("pureclass: ", pureclass nsobjectprotocol) print("swiftobject: ", swiftobject nsobjectprotocol)  print("\n*anyclass print*") print("nsobject: ", nsobject) print("wkrequestclass: ", wkrequestclass) print("sighclass: ", sighclass) print("pureclass: ", pureclass) print("swiftobject: ", swiftobject)  print("\n*type print*")  print("type of nsobject: ", type(of: nsobject)) print("type of wkrequestclass: ", type(of: wkrequestclass)) print("type of sighclass: ", type(of: sighclass)) print("type of pureclass: ", type(of: pureclass)) print("type of swiftobject: ", type(of: swiftobject))  print("\n*.self print*")  print("nsobject.self: ", nsobject.self) print("wkrequestclass.self: ", wkrequestclass.self) print("sighclass.self: ", sighclass.self) print("pureclass.self: ", pureclass.self) print("swiftobject.self: ", swiftobject.self)  print("\n*superclass print*")  print("nsobject superclass: ", nsobject.superclass() ?? "nil") //print("wkrequestclass superclass: ", wkrequestclass.superclass()) print("wkrequestclass superclass: crash") print("sighclass superclass: ", sighclass.superclass() ?? "nil") print("pureclass superclass: ", pureclass.superclass() ?? "nil") print("swiftobject superclass: ", swiftobject.superclass() ?? "nil")  print("\n*introspection*\n")  var count: uint32 = 0 var protocols = class_copyprotocollist(wkrequestclass, &count);  i: int in 0..<int(count) {     print("wkrequestclass implements", protocols![i]!) }  print("wkrequestclass superclass is", class_getsuperclass(wkrequestclass)) print("its super super class is", class_getsuperclass(class_getsuperclass(wkrequestclass)))  //introspecting wkobject protocols = class_copyprotocollist(class_getsuperclass(wkrequestclass), &count);  i: int in 0..<int(count) {     print("wkobject implements", protocols![i]!) }  print("wkobject conforms nsobjectprotocol? ", class_conformstoprotocol(class_getsuperclass(wkrequestclass), nsobjectprotocol.self)) 

in easy playground play bit different class types, , @ end try introspect wknsurlrequest , wkobject using objective-c runtime.

if crash due runtime bug expecting crash in introspection section well, nothing. no problems @ all.

this output:

 **nsobjectprotocol conformance**   - nsobject:  true   - wkrequestclass: crash   - sighclass:  true  - pureclass:  true   - swiftobject:  true  **anyclass print**   - nsobject:  nsobject  - wkrequestclass:  wknsurlrequest  - sighclass:  sigh  - pureclass:  pureclass  - swiftobject:  swiftobject  **type print**   - type of nsobject:  nsobject.type  - type of wkrequestclass:  wknsurlrequest.type  - type of sighclass:  sigh.type  - type of pureclass:  pureclass.type  - type of swiftobject:  swiftobject.type  **.self print**   - nsobject.self:  nsobject  - wkrequestclass.self:  wknsurlrequest  - sighclass.self:  sigh  - pureclass.self:  pureclass  - swiftobject.self:  swiftobject  **superclass print**   - nsobject superclass:  nil  - wkrequestclass superclass: crash  - sighclass superclass:  nsobject  - pureclass superclass:  swiftobject  - swiftobject superclass:  nil  **introspection**   - wkrequestclass implements ``  - wkrequestclass superclass wkobject  - super super class nil  - wkobject implements ``  - wkobject conforms nsobjectprotocol?  true 

funny fact, if do

wkrequestclass.issubclass(of: class_getsuperclass(wkrequestclass)) 

i crash, absurd.

does proves objective c runtime broken/doesn't handle correctly case? answer doesn't easy (that0s why i'm posting question) because, expected, wkobject conforming nsobjectprotocol, , root class superclass nil. worked kind of introspections.

what remains check swift runtime. there way check it? there missed explain crash? i'm curious know opinion that.

you correct wkobject implements nsobject protocol implements wkobject protocol , protocol inherits nsobject protocol. plays no role here.

certain methods +issubclassofclass: or +instancesrespondtoselector: not declared in nsobject protocol, these normal class methods of nsobject class , inherited sub-classes of nsobject sub-classes of nsobject. other root classes must implement these if want nsobject compatible, nsobject protocol won't force them so.

now check out code unit test class:

sel issubclasssel = @selector(issubclassofclass:); protocol * nsobjp = @protocol(nsobject); class c1 = nsclassfromstring(@"nsobject"); xctassert(c1); xctassert([c1 conformstoprotocol:nsobjp]); xctassert([c1 instancesrespondtoselector:issubclasssel]); xctassert([c1 issubclassofclass:[nsobject class]]);  class c2 = nsclassfromstring(@"wknsurlrequest"); xctassert(c2); xctassert([c2 conformstoprotocol:nsobjp]); // line 1 xctassert([c2 instancesrespondtoselector:issubclasssel]); // line 2 xctassert([c2 issubclassofclass:[nsobject class]]); // line 3 

this code crashes @ line 2:

thread 1: exc_bad_access (code=1, address=0x18) 

and if comment out line 2, code still crashes @ line 3 same error. note not swift code, nor in way swift related, pure objective-c code. it's wrong objective-c code, see below.

so wkobject implement +conformstoprotocol: (line 1 not crash), has to, requirement of nsobject protocol, doesn't implement +instancesrespondtoselector: or +issubclassofclass:, , doesn't have to, okay. root class, doesn't inherit nsobject , there no protocol require implement of these. mistake above call these methods; calling not-existing methods on objects "undefined behavior" , allows runtime pretty anything: ignoring call, logging error, throwing exception, or crashing right away; , objc_msgsend() highly optimized function (it has no security checks, expensive every call), crashes.

but apparently swift doesn't seem care. when dealing obj-c objects, swift seems assume can call 1 of theses methods nsobject , sub-class of implement, though no protocol promise that. , that's why swift code constructs cause crash objective-c root objects don't inherit nsobject. , assumption wrong. swift must never call methods on root objects doesn't know sure these methods implemented. called bug in swift-objc-bridge @ other question.

update 1:

giuseppe lanza asked:

why when have pure swift class, class string , test nsobjectprotocol true?

personally think bug in swift runtime. pure swift class not conform nsobjectprotocol. cannot conform it, see answer below.

giuseppe lanza asked:

please note if create protocol inherits nsobjectprotocol , try make pureclass conformance protocol compiler complain pureclass not nsobjectprotocol compliant

that's because pureclass have implement required nsobjectprotocol methods conform protocol; see answer https://stackoverflow.com/a/24650406/15809

however, cannot satisfy requirement, 1 requirement of nsobjectprotocol implement method

func `self`() -> self 

and that's not possible pure swift class, when try that, compiler complain:

error: method cannot implementation of @objc requirement because result type cannot represented in objective-c 

which correct, pure swift class cannot represented in obj-c, cannot return required type.

the swift documentation says:

note @objc protocols can adopted classes inherit objective-c classes or other @objc classes.

and @objc forces inherit nsobject, pure swift class not.


Comments

Popular posts from this blog

Command prompt result in label. Python 2.7 -

javascript - How do I use URL parameters to change link href on page? -

amazon web services - AWS Route53 Trying To Get Site To Resolve To www -