Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save luiseduardohdbackup/c27976a78f659355e66c to your computer and use it in GitHub Desktop.
Save luiseduardohdbackup/c27976a78f659355e66c to your computer and use it in GitHub Desktop.
Swift and Objective-C Class Parsing
////////////////////////////////////////////////
//
// Swift and Objective-C Class Parsing
//
////////////////////////////////////////////////
import Foundation
// Class parsing
enum ClassType {
case Swift, ObjectiveC
func toString() -> String {
switch self {
case .Swift:
return "Swift"
case .ObjectiveC:
return "Objective-C"
}
}
}
struct ParsedClass {
let type: ClassType
let name: String
let mangledName: String?
let moduleName: String?
}
extension String {
subscript (r: Range<Int>) -> String {
get {
let startIndex = advance(self.startIndex, r.startIndex)
let endIndex = advance(startIndex, r.endIndex)
return self[Range(start: startIndex, end: endIndex)]
}
}
}
func parseClass(aClass: AnyClass) -> ParsedClass {
// Swift mangling details found here: http://www.eswick.com/2014/06/inside-swift
let originalName = NSStringFromClass(aClass)
if !originalName.hasPrefix("_T") {
// Not a Swift symbol
return ParsedClass(type: ClassType.ObjectiveC,
name: originalName,
mangledName: nil,
moduleName: nil)
}
let originalNameLength = originalName.utf16count
var cursor = 4
var substring = originalName[cursor..originalNameLength-cursor]
// Module
let moduleLength = substring.bridgeToObjectiveC().integerValue
let moduleLengthLength = "\(moduleLength)".utf16count
let moduleName = substring[moduleLengthLength..moduleLength]
// Update cursor and substring
cursor += moduleLengthLength + moduleName.utf16count
substring = originalName[cursor..originalNameLength-cursor]
// Class name
let classLength = substring.bridgeToObjectiveC().integerValue
let classLengthLength = "\(classLength)".utf16count
let className = substring[classLengthLength..classLength]
return ParsedClass(type: ClassType.Swift,
name: className,
mangledName: originalName,
moduleName: moduleName)
}
// Playground start
class MySwiftClass {
// Empty class
}
var parsedClass = parseClass(MySwiftClass.self)
parsedClass.type.toString()
parsedClass.name
parsedClass.mangledName!
parsedClass.moduleName!
parsedClass = parseClass(NSObject.self)
parsedClass.type.toString()
parsedClass.name
parsedClass.mangledName!
parsedClass.moduleName!
func demangle(className: String) -> String {
let tmpClassName = ("__TMP" + className).bridgeToObjectiveC().UTF8String
let propertyName: CString = "tmpProperty"
let tmpClass: AnyClass! = objc_allocateClassPair(NSObject.self, tmpClassName, 0)
objc_registerClassPair(tmpClass)
let propertyType = "@\"\(className)\"".bridgeToObjectiveC().UTF8String
let attr = objc_property_attribute_t(name: "T", value: propertyType)
class_addProperty(tmpClass, propertyName, [attr], 1)
let property = class_getProperty(tmpClass, propertyName)
var attCount: CUnsignedInt = 0;
let atts = property_copyAttributeList(property, &attCount)
objc_disposeClassPair(tmpClass)
return "\(atts[0].value)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment