"We need to get ahold of a class given a name" is definitely a requirement to do NSCoding right. I'm not at all convinced dlsym is a valid long-term answer for that, though. If you have an 'internal' class, it doesn't (currently) have a public symbol that you can use dlsym for.
This sort of goes with the existing problem of static registration: there's no pure Swift way to get all subclasses of a class, or to get a class from a name for any other reason. That's a general language problem, though, and we should discuss it on swift-dev. Jordan > On Dec 23, 2015, at 15:12, Philippe Hausler <[email protected]> wrote: > > NSCoding will have to use something to transform from strings to classes, and > that satisfy the two cases (or more) that we have already shown, currently > there is no thing that does that in either form; either mangled or non > mangled. Basically we need something to implement NSClassFromString with. > Which we have clearly shown that dlsym does not fully meet the needs since > there are cases that will emit as “module.classname” and others that emit as > the mangled name. The simple case is probably going to be the a very common > usage pattern for consumers (and of previously built applications). The inner > class should definitely be handled in addition to this case. > > Are there any methods that can fetch the name (either the symbolic or the > readable) given a AnyClass in the runtime to get work started here? I think > it is definitely sensible as a start to restrict this just to descendants of > the class NSObject. I would presume that since the Metadata is potentially > volatile contents we should use something along the lines of > swift_getTypeName etc? > >> On Dec 23, 2015, at 2:53 PM, Jordan Rose <[email protected] >> <mailto:[email protected]>> wrote: >> >> Here's another example on OS X: >> >> import Foundation >> >> class Outer { >> class Inner : NSObject, NSCoding { >> let uuid: Foundation.NSUUID >> required init?(coder aDecoder: NSCoder) { >> uuid = aDecoder.decodeObjectForKey("my.uuid") as! >> Foundation.NSUUID >> } >> override init() { >> uuid = Foundation.NSUUID() >> } >> func encodeWithCoder(aCoder: NSCoder) { >> aCoder.encodeObject(uuid, forKey: "my.uuid") >> } >> } >> } >> >> NSKeyedArchiver.archiveRootObject(Outer.Inner(), toFile: >> "/Users/jrose/Desktop/test-archive") >> >> >> Which results in this archive: >> >> { >> "$version" => 100000 >> "$objects" => [ >> 0 => "$null" >> 1 => { >> "my.uuid" => <CFKeyedArchiverUID 0x7f8992c0e9d0 >> [0x7fff7c5acd80]>{value = 2} >> "$class" => <CFKeyedArchiverUID 0x7f8992c0ec90 [0x7fff7c5acd80]>{value >> = 4} >> } >> 2 => { >> "NS.uuidbytes" => <67f0b08b c8274f8c b0c78d90 bd4627dc> >> "$class" => <CFKeyedArchiverUID 0x7f8992c0eda0 [0x7fff7c5acd80]>{value >> = 3} >> } >> 3 => { >> "$classname" => "NSUUID" >> "$classes" => [ >> 0 => "NSUUID" >> 1 => "NSObject" >> ] >> } >> 4 => { >> "$classname" => "_TtCC4main5Outer5Inner" >> "$classes" => [ >> 0 => "_TtCC4main5Outer5Inner" >> 1 => "NSObject" >> ] >> } >> ] >> "$archiver" => "NSKeyedArchiver" >> "$top" => { >> "root" => <CFKeyedArchiverUID 0x7f8992c0f0c0 [0x7fff7c5acd80]>{value = 1} >> } >> } >> >> NSStringFromClass makes pretty names when they fall into the "simple" >> category, but that's not an arbitrarily extensible transformation, and >> NSCoding shouldn't have to know anything about it. >> >> Jordan >> >>> On Dec 23, 2015, at 14:48, Philippe Hausler <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>> The archiving format encodes the names of the classes in the archive >>> itself. Here are a few code examples and a quasi readable output from them: >>> >>> let uuid = NSUUID() >>> let data = NSKeyedArchiver.archivedDataWithRootObject(uuid) >>> let archive = try! NSPropertyListSerialization.propertyListWithData(data, >>> options: [], format: nil) >>> print(archive) >>> >>> prints the following: >>> >>> { >>> "$archiver" = NSKeyedArchiver; >>> "$objects" = ( >>> "$null", >>> { >>> "$class" = "<CFKeyedArchiverUID 0x1030025e0 >>> [0x7fff7ab33bb0]>{value = 2}"; >>> "NS.uuidbytes" = <797639fe dad74b14 902afab3 c490448b>; >>> }, >>> { >>> "$classes" = ( >>> NSUUID, >>> NSObject >>> ); >>> "$classname" = NSUUID; >>> } >>> ); >>> "$top" = { >>> root = "<CFKeyedArchiverUID 0x103002a80 [0x7fff7ab33bb0]>{value = >>> 1}"; >>> }; >>> "$version" = 100000; >>> } >>> >>> Note the $classes and $classname objects; which are what tell the internal >>> implementation of NSKeyedUnarchiver what to construct; moreover you can >>> create your own classes.. >>> >>> // I don’t really think this is a good naming for an application’s class >>> but hey it might happen... >>> class NSUUID : NSObject, NSCoding { >>> let uuid: Foundation.NSUUID >>> required init?(coder aDecoder: NSCoder) { >>> uuid = aDecoder.decodeObjectForKey("my.uuid") as! Foundation.NSUUID >>> } >>> override init() { >>> uuid = Foundation.NSUUID() >>> } >>> func encodeWithCoder(aCoder: NSCoder) { >>> aCoder.encodeObject(uuid, forKey: "my.uuid") >>> } >>> } >>> >>> let uuid = NSUUID() >>> let data = NSKeyedArchiver.archivedDataWithRootObject(uuid) >>> let archive = try! NSPropertyListSerialization.propertyListWithData(data, >>> options: [], format: nil) >>> print(archive) >>> >>> prints the following: >>> >>> { >>> "$archiver" = NSKeyedArchiver; >>> "$objects" = ( >>> "$null", >>> { >>> "$class" = "<CFKeyedArchiverUID 0x100709630 >>> [0x7fff7ab33bb0]>{value = 4}"; >>> "my.uuid" = "<CFKeyedArchiverUID 0x100708e60 >>> [0x7fff7ab33bb0]>{value = 2}"; >>> }, >>> { >>> "$class" = "<CFKeyedArchiverUID 0x100709740 >>> [0x7fff7ab33bb0]>{value = 3}"; >>> "NS.uuidbytes" = <546e5b5e 15c244a1 aa96eb90 30c3f7f6>; >>> }, >>> { >>> "$classes" = ( >>> NSUUID, >>> NSObject >>> ); >>> "$classname" = NSUUID; >>> }, >>> { >>> "$classes" = ( >>> "Archiver.NSUUID", >>> NSObject >>> ); >>> "$classname" = "Archiver.NSUUID"; >>> } >>> ); >>> "$top" = { >>> root = "<CFKeyedArchiverUID 0x100709b70 [0x7fff7ab33bb0]>{value = >>> 1}"; >>> }; >>> "$version" = 100000; >>> } >>> >>> Granted this is a questionable name for a class but it illustrates which >>> class names are encoded where and how they should be interpreted in the >>> pre-existing archive format; which we will have to figure out some sensible >>> way of inflating and deflating to/from disk/network etc. >>> >>>> On Dec 23, 2015, at 2:37 PM, Jordan Rose <[email protected] >>>> <mailto:[email protected]>> wrote: >>>> >>>> No, we cannot encode things "non-mangled but with the namespace". For any >>>> type other than top-level non-generic class types, using a non-mangled >>>> name is not unique. The only correct answer for arbitrary classes is to >>>> use mangled names, or something that maps one-to-one with mangled names. >>>> >>>> Now, Foundation classes are not arbitrary classes, but then I don't see >>>> why we'd need to use mangled names for those. We can just use the plain >>>> old Objective-C names that the OS X classes use today. >>>> >>>> Jordan >>>> >>>>> On Dec 22, 2015, at 10:16, Philippe Hausler via swift-corelibs-dev >>>>> <[email protected] <mailto:[email protected]>> >>>>> wrote: >>>>> >>>>> To clarify the goals: I think it is reasonable for us to have a goal to >>>>> be able to encode/decode archives from foreign targets; e.g. linux >>>>> encodes an archive and mac os x decodes or iOS encodes and linux decodes. >>>>> This will allow for server architecture to transmit binary archives >>>>> across the wire. This will mean that we will want to have the encoded >>>>> class names from the application scope to be encoded as the non mangled >>>>> name but with the namespace. However this presents a problem; Foundation >>>>> will have a namespace which will need to be inferred both for encoding >>>>> and decoding. Thankfully there may be a reasonable way to approach this; >>>>> >>>>> public class func classNameForClass(cls: AnyClass) -> String? >>>>> public class func setClassName(codedName: String?, forClass cls: AnyClass) >>>>> >>>>> These methods can be used to allow for translation of classes by >>>>> registering the appropriate classes for a “shortened” name that drops the >>>>> Foundation/SwiftFoundation namespace prefix during encoding. >>>>> >>>>>> On Dec 22, 2015, at 2:45 AM, Luke Howard via swift-corelibs-dev >>>>>> <[email protected] <mailto:[email protected]>> >>>>>> wrote: >>>>>> >>>>>> >>>>>>> On 22 Dec 2015, at 5:50 AM, Jordan Rose <[email protected] >>>>>>> <mailto:[email protected]>> wrote: >>>>>>> >>>>>>> IMHO on Linux NSKeyedArchiver should always use mangled names. If we >>>>>>> want cross-platform archives, we should set up standard substitutions, >>>>>>> but given that Swift classes exposed to Objective-C are archived with >>>>>>> their full names it doesn't make sense to use "half the name" in the >>>>>>> archive. >>>>>> >>>>>> You mean namespaced but unmangled yes? If so I agree. >>>>>> >>>>>> BTW I found a couple of small CF nits: >>>>>> >>>>>> * in CFDictionaryGetKeysAndValues(), keybuf and valuebuf are transposed >>>>>> in the call to CF_SWIFT_FUNCDISPATCHV(NSDictionary.getObjects()) >>>>>> >>>>>> * _CFSwiftDictionaryGetKeysAndValues() does not handle keybuf or valbuf >>>>>> being NULL (either of which are valid when calling >>>>>> CFDictionaryGetKeysAndValues()) >>>>>> >>>>> >>>>> This is a bit un-related to NSCoding and the transposition is probably a >>>>> mistake if it is inverted (the CF method should be reversed from the NS >>>>> method to mimic the objc counterpart) >>>>> >>>>>> — Luke >>>>>> _______________________________________________ >>>>>> swift-corelibs-dev mailing list >>>>>> [email protected] <mailto:[email protected]> >>>>>> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev >>>>>> <https://lists.swift.org/mailman/listinfo/swift-corelibs-dev> >>>>> >>>>> _______________________________________________ >>>>> swift-corelibs-dev mailing list >>>>> [email protected] <mailto:[email protected]> >>>>> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev >>>>> <https://lists.swift.org/mailman/listinfo/swift-corelibs-dev> >>> >> >
_______________________________________________ swift-corelibs-dev mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
