Can you get __FUNCTION__ from the caller? - swift

Example:
#noreturn func setOnlyPropertyGetterError(__function__: String) {
fatalError("\(__function__) is set-only")
}
var property: Property {
get {setOnlyPropertyGetterError(__FUNCTION__)}
set {//useful work}
}
Can we avoid having to pass __FUNCTION__?

I think this is what you want to achieve:
#noreturn func writeOnlyProperty(propertyName: String = __FUNCTION__) {
fatalError("Property \(propertyName) is write-only")
}
class Foo {
var blackHole: Int {
get { writeOnlyProperty() }
set { print("Consuming value \(newValue)") }
}
}
let foo = Foo()
foo.blackHole = 1 // Prints "Consuming value 1"
let bar = foo.blackHole // Produces fatal error "Property blackHole is write-only"

Related

Using a Function Argument as a Dynamic Variable

Is there any way to make this work without resorting to calling the subscript directly?
#dynamicMemberLookup
final class Fuzzy {
private var backing: [String: String] = [:]
subscript(dynamicMember key: String) -> String? {
get {
return backing[key]
}
set {
backing[key] = newValue
}
}
}
let fuzz = Fuzzy()
func worksFine() {
fuzz.hello = "hi :)"
print(fuzz.hello!)
}
// *** HERE WOULD LIKE TO PASS ARG DYNAMICALLY
func canThisWork(with arg: String) {
print(fuzz\.arg)
}
You can probably use KeyPath if you only want to access the value:
func canThisWork(with arg: KeyPath<Fuzzy, String?>) {
print(fuzz[keyPath: arg]!)
}
Or WritableKeyPath if you also want to mutate it:
var fuzz = Fuzzy()
func canThisWork(with arg: WritableKeyPath<Fuzzy, String?>) {
fuzz[keyPath: arg] = "hi :)"
print(fuzz[keyPath: arg]!)
}
In both cases you call your function like this:
canThisWork(with: \.hello)

Inheritance of property methods (set, get, didSet, willSet, etc.) in Swift

My question is how to deal with inheritance of property methods such as set, get, didSet, willSet, ...?
Let's take an example: I want to override the setter method of a property in a Swift class. Here is what I want to achieve (which is obviously not working):
class A {
var value: Int {get {...} set {...} }
}
class B: A {
var value: Int {
set(newValue) {
// do some fancy stuff...
}
}
}
This is not working, too:
// in class B
override func setValue(newValue: Int) {
// do some fancy stuff...
}
We can do in Swift something like this:
class A {
var _value: Int = 0
var value: Int {
get {
return _value
}
set {
_value = newValue
}
}
}
class B: A {
override var value: Int {
get {
return _value
}
set {
_value = newValue + 1
}
}
}
let a = A()
a.value = 1
print(a.value) // => 1
let b = B()
b.value = 1
print(b.value) // => 2
This approach is not very elegant because I have to implement also the getter methods, which is actually not necessary, because only the setter should be overridden.
You could do:
class A {
var value: Int = 0
}
class B: A {
override var value: Int {
get { return super.value }
set {
// Something fancy...
super.value = newValue
}
}
}
While you still have to implement a getter in B, you at least don't need _value, which helps keeps class A clean.
Unfortunately your only way to do this would be to create a separate get and set method if you really wanted to do this.
class A {
private var value: Int = 0
func getValue() -> Int { return value }
func setValue(newValue : Int) {
value = newValue
}
}
By the nature of using computed properties you are basically doing a "shortcut" in some ways over making two separate methods - and as thus you would have to override both the set and get if you wanted to change things.
Depending on your usage an override of didSet could do the trick (based on your last example):
class B: A {
override var value: Int {
didSet {
_value++
}
}
}

Variable used within its own initial value while variable is used inside a closure past init

typealias CBType = () -> Void
class A {
let b = B()
func test() {
let token = b.register { CBType in
self.b.waitFor([token]) // ERROR: Variable used within its own initial value
}
b.dispatch()
}
}
class B {
private var _callbacks = [String:CBType]()
func register(callback: CBType) -> String {
let id = "1234"
_callbacks[id] = callback
return id
}
func dispatch() {
for (_, cb) in self._callbacks {
cb()
}
}
func waitFor(tokens: [String]) {
}
}
A().test()
When I modify the test function to use a instance variable, things are working again but that syntax feels a bit heavy.
class A {
let b = B()
var token: String?
func test() {
token = b.register { CBType in
self.b.waitFor([self.token!])
}
b.dispatch()
}
}
Why can't I use a local variable in the closure since it will be way past initialization when the closure is finally called?
The constant token doesn't have a value at the time it is captured by the closure.
You can use a mutable variable instead, and the closure will capture the variable rather the its value.
func test() {
var token = ""
token = b.register {
self.b.waitFor([token])
}
b.dispatch()
}
Alternatively, you can pass the token as a parameter into the closure:
typealias CBType = (String) -> Void
class A {
let b = B()
func test() {
let token = b.register { theToken in
self.b.waitFor([theToken])
}
b.dispatch()
}
}
class B {
private var _callbacks = [String:CBType]()
func register(callback: CBType) -> String {
let id = "1234"
_callbacks[id] = callback
return id
}
func dispatch() {
for (id, cb) in self._callbacks {
cb(id)
}
}
func waitFor(tokens: [String]) {
println("Wait for \(tokens)")
}
}
A().test()
In your first example, token doesn't have a value when you make the call self.b.waitFor([token]).
In your second example, everything appears to work because by declaring token like so: var token: String? it is given an initial value (nil).
The issue isn't whether you are using an instance variable -vs- a local variable (or that it's being used within a closure), the issue is that (in the first example) you are trying to use the token within the expression that provides its initial value.
Equivalent to this would be declaring an Int like so: let myValue: Int = myValue + 1 - its initial value is supposed to be "what" + 1?

get the type/class of a property from its name in swift

Lets say I have this class:
class Node {
var value: String
var children: [Node]?
}
If I have the name of one of its properties (for example "children") how can I get its type? (In this case [Node]?)
I imagine having a global function like below will solve my needs:
func typeOfPropertyWithName(name: String, ofClass: AnyClass) -> AnyClass? {
//???
}
// Example usage:
var arrayOfNodesClass = typeOfPropertyWithName("children", Node.self)
Swift 2 (Note: Reflection changed):
import Foundation
enum PropertyTypes:String
{
case OptionalInt = "Optional<Int>"
case Int = "Int"
case OptionalString = "Optional<String>"
case String = "String"
//...
}
extension NSObject{
//returns the property type
func getTypeOfProperty(name:String)->String?
{
let type: Mirror = Mirror(reflecting:self)
for child in type.children {
if child.label! == name
{
return String(child.value.dynamicType)
}
}
return nil
}
//Property Type Comparison
func propertyIsOfType(propertyName:String, type:PropertyTypes)->Bool
{
if getTypeOfProperty(propertyName) == type.rawValue
{
return true
}
return false
}
}
custom class:
class Person : NSObject {
var id:Int?
var name : String?
var email : String?
var password : String?
var child:Person?
}
get the type of the "child" property:
let person = Person()
let type = person.getTypeOfProperty("child")
print(type!) //-> Optional<Person>
property type checking:
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalInt) ) //--> false
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalString) //--> true
or
if person.propertyIsOfType("email", type: PropertyTypes.OptionalString)
{
//true -> do something
}
else
{
//false -> do something
}
Reflection is achieved in Swift using the global reflect() function. When passing an instance of some type to reflect() it returns a MirrorType, which has a range of properties allowing you to analyze your instance:
var value: Any { get }
var valueType: Any.Type { get }
var objectIdentifier: ObjectIdentifier? { get }
var count: Int { get }
var summary: String { get }
var quickLookObject: QuickLookObject? { get }
var disposition: MirrorDisposition { get }
subscript(i: Int) -> (String, MirrorType) { get }
This seems to work:
func getTypeOfVariableWithName(name: String, inInstance instance: Any) -> String? {
let mirror = reflect(instance)
var variableCollection = [String: MirrorType]()
for item in 0..<mirror.count {
variableCollection[mirror[item].0] = mirror[item].1
}
if let type = variableCollection[name] {
let longName = _stdlib_getDemangledTypeName(type.value)
let shortName = split(longName, { $0 == "."}).last
return shortName ?? longName
}
return nil
}
Here's some example code on SwiftStub.
Edit:
The result for optional values is only "Optional".
The result for arrays is only "Array".
The result for dictionaries is only "Dictionary".
I'm not sure if it is possible to extract what kind of optional/array/dictionary it is. But I guess this would also be the case for custom data structures using generics.
Building on #PeterKreinz answer I needed to be able to check types of inherited properties as well so added a little to his above code:
extension NSObject {
// Returns the property type
func getTypeOfProperty (name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
while let parent = type.superclassMirror() {
for child in parent.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
type = parent
}
return nil
}
}
Hope this may help someone.
Swift 3 update:
// Extends NSObject to add a function which returns property type
extension NSObject {
// Returns the property type
func getTypeOfProperty (_ name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
while let parent = type.superclassMirror {
for child in parent.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
type = parent
}
return nil
}
}
The solution provided by #peter-kreinz using Swift's class Mirror works beautifully when you have an instance of a class, and want to know the types of the properties. However if you want to inspect the properties of a class without having an instance of it you might be interested in my solution.
I have a solution that finds the name and type of a property given any class that inherits from NSObject.
I wrote a lengthy explanation on StackOverflow here, and my project is available here on Github,
In short you can do something like this (but really check out the code Github):
public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
var count = UInt32()
guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
var types: Dictionary<String, Any> = [:]
for i in 0..<Int(count) {
guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
let type = getTypeOf(property: property)
types[name] = type
}
free(properties)
return types
}

Swift generic cast to Protocol fails with swift_dynamicCastUnknownClass

The following example is taken from Apple Swift Reference guide. I only added the getHasAreaInstances() and getGenericHasAreaInstances()
import UIKit
#objc protocol HasArea {
var area: Double { get }
}
#objc protocol HasExtendedArea: HasArea {
var extendedArea: Double { get }
}
class Circle: HasArea {
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius }
init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
var area: Double
init(area: Double) { self.area = area }
}
class Continent: HasExtendedArea {
var area: Double { return 300 }
var extendedArea: Double { return 3000 }
}
let objects: [HasArea] = [
Circle(radius: 2.0),
Country(area: 243_610),
Continent()
]
for object in objects {
if let objectWithArea = object as? HasExtendedArea {
println("Extended Area is \(objectWithArea.area)")
} else {
println("Area is not extended")
}
}
// Extended Area is 300.0
// Area is not extended
// Area is not extended
The method below returns the correct array:
func getHasExtendedAreaInstances() -> [HasExtendedArea] {
var haveArea: [HasExtendedArea] = []
for object in objects {
if let objectWithArea = object as? HasExtendedArea {
haveArea.append(objectWithArea)
}
}
return haveArea
}
let areas = getHasExtendedAreaInstances()
//[Continent]
The method below returns the correct array:
func getGenericHasExtendedAreaInstances<T>() -> [T] {
var haveArea: [T] = []
for object in objects {
if let objectWithArea = object as? T {
haveArea.append(objectWithArea)
}
}
return haveArea
}
let areasGeneric: [HasExtendedArea] = getGenericHasExtendedAreaInstances()
//[Continent]
However, as soon as a constraint is imposed on the generic type, it no longer works
func getGenericConstraintHasExtendedAreaInstances<T: HasArea>() -> [T] {
var haveArea: [T] = []
for object in objects {
if let objectWithArea = object as? T {
// the line above fails with swift_dynamicCastUnknownClass
haveArea.append(objectWithArea)
}
}
return haveArea
}
let areasGenericConstraint: [HasExtendedArea] = getGenericConstraintHasExtendedAreaInstances()
Your generic function makes no sense. What would resolve it? What would satisfy it? Make a simpler example with the same basic declaration structure: it's an impossible function. For example, start with this nongeneric function:
class Thing : Printable {
var description : String {return "thing"}
}
func g() -> [Thing] {
return [Thing()]
}
let result : [Thing] = g()
Now modify g to be generic, exactly parallel to your function:
class Thing : Printable {
var description : String {return "thing"}
}
func g<T:Printable>() -> [T] {
return [Thing()]
}
let result : [Thing] = g()
It doesn't compile - because it makes no sense.
This is fixed in Swift 1.2, tested on Xcode 6.3 Beta 3
You can specify the type constraint without swift compiler failing on you