Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ObjectiveKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
344C27861DD5CDCF008AA223 /* ObjectiveKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 344C27781DD5CDCF008AA223 /* ObjectiveKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
344C27901DD5CFAB008AA223 /* ObjectiveClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344C278F1DD5CFAB008AA223 /* ObjectiveClass.swift */; };
344C27941DD6F4E1008AA223 /* RuntimeClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344C27931DD6F4E1008AA223 /* RuntimeClass.swift */; };
D7D1F6F71E4BAE4200C6E22E /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D1F6F61E4BAE4200C6E22E /* Optional+Extensions.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -35,6 +36,7 @@
344C27851DD5CDCF008AA223 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
344C278F1DD5CFAB008AA223 /* ObjectiveClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectiveClass.swift; sourceTree = "<group>"; };
344C27931DD6F4E1008AA223 /* RuntimeClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuntimeClass.swift; sourceTree = "<group>"; };
D7D1F6F61E4BAE4200C6E22E /* Optional+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Optional+Extensions.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -82,6 +84,7 @@
344C27931DD6F4E1008AA223 /* RuntimeClass.swift */,
344553051DDA6C1B007852A1 /* RuntimeModification.swift */,
344C27791DD5CDCF008AA223 /* Info.plist */,
D7D1F6F61E4BAE4200C6E22E /* Optional+Extensions.swift */,
);
path = ObjectiveKit;
sourceTree = "<group>";
Expand Down Expand Up @@ -174,6 +177,7 @@
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 344C276B1DD5CDCF008AA223;
productRefGroup = 344C27761DD5CDCF008AA223 /* Products */;
Expand Down Expand Up @@ -209,6 +213,7 @@
buildActionMask = 2147483647;
files = (
344C27901DD5CFAB008AA223 /* ObjectiveClass.swift in Sources */,
D7D1F6F71E4BAE4200C6E22E /* Optional+Extensions.swift in Sources */,
344553061DDA6C1B007852A1 /* RuntimeModification.swift in Sources */,
344C27941DD6F4E1008AA223 /* RuntimeClass.swift in Sources */,
);
Expand Down
96 changes: 39 additions & 57 deletions ObjectiveKit/ObjectiveClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ typealias ImplementationBlock = @convention(block) () -> Void

/// An object that allows you to introspect and modify classes through the ObjC runtime.
public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {

private typealias RuntimeCopyingGetter<Type> = (AnyClass?, UnsafeMutablePointer<UInt32>?) -> UnsafeMutablePointer<Type?>!

public var internalClass: AnyClass

Expand All @@ -28,81 +30,61 @@ public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
///
/// - Returns: An array of instance variables.
public var ivars: [String] {
get {
var count: CUnsignedInt = 0
var ivars = [String]()
let ivarList = class_copyIvarList(internalClass, &count)
for i in (0..<Int(count)) {
let unwrapped = ivarList?[i].unsafelyUnwrapped
if let ivar = ivar_getName(unwrapped) {
let string = String(cString: ivar)
ivars.append(string)
}
}
free(ivarList)
return ivars
}
return self.runtimeStrings(with: { class_copyIvarList($0, $1) }, transform: ivar_getName)
}


/// Get all selectors implemented by the class.
///
/// - Returns: An array of selectors.
public var selectors: [Selector] {
get {
var count: CUnsignedInt = 0
var selectors = [Selector]()
let methodList = class_copyMethodList(internalClass, &count)
for i in (0..<Int(count)) {
let unwrapped = methodList?[i].unsafelyUnwrapped
if let selector = method_getName(unwrapped) {
selectors.append(selector)
}
}
free(methodList)
return selectors
}
return self.runtimeEntities(with: { class_copyMethodList($0, $1) }, transform: method_getName)
}

/// Get all protocols implemented by the class.
///
/// - Returns: An array of protocol names.
public var protocols: [String] {
get {
var count: CUnsignedInt = 0
var protocols = [String]()
let protocolList = class_copyProtocolList(internalClass, &count)
for i in (0..<Int(count)) {
let unwrapped = protocolList?[i].unsafelyUnwrapped
if let protocolName = protocol_getName(unwrapped) {
let string = String(cString: protocolName)
protocols.append(string)
}
}
return protocols
}
return self.runtimeStrings(
with: { UnsafeMutablePointer(mutating: class_copyProtocolList($0, $1)) },
transform: protocol_getName
)
}

/// Get all properties implemented by the class.
///
/// - Returns: An array of property names.
public var properties: [String] {
get {
var count: CUnsignedInt = 0
var properties = [String]()
let propertyList = class_copyPropertyList(internalClass, &count)
for i in (0..<Int(count)) {
let unwrapped = propertyList?[i].unsafelyUnwrapped
if let propretyName = property_getName(unwrapped) {
let string = String(cString: propretyName)
properties.append(string)
}
}
free(propertyList)
return properties
return self.runtimeStrings(with: { class_copyPropertyList($0, $1) }, transform: property_getName)
}

// MARK: Private

private func runtimeEntities<Type, Result>(
with copyingGetter: RuntimeCopyingGetter<Type>,
transform: (Type) -> Result?
)
-> [Result]
{
var cCount: CUnsignedInt = 0

let entities = copyingGetter(self.internalClass, &cCount)
let count = Int(exactly: cCount) ?? 0

defer { entities?.deallocate(capacity: count) }

return UnsafeMutableBufferPointer(start: entities, count: count)
.flatMap(identity)
.flatMap(transform)
}

private func runtimeStrings<Type>(
with copyingGetter: RuntimeCopyingGetter<Type>,
transform: (Type!) -> UnsafePointer<Int8>!
)
-> [String]
{
return self.runtimeEntities(with: copyingGetter) {
pure(transform($0)).map(String.init(cString:))
}
}

}


17 changes: 17 additions & 0 deletions ObjectiveKit/Optional+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Optional+Extensions.swift
// ObjectiveKit
//
// Created by Oleksa 'trimm' Korin on 2/8/17.
// Copyright © 2017 Roy Marmelstein. All rights reserved.
//

/// Wraps value in optional
public func pure<T>(_ value: T) -> T? {
return value
}

/// Returns the value passed as the parameter
public func identity<T>(_ value: T) -> T {
return value
}