Swift: reflection of protocol variables
Computed properties are not represented in the runtime introspection provided by Mirror
From the Language Reference - Mirror struct (emphasis added by me)
Representation of the sub-structure and optional "display style" of
any arbitrary subject instance.Describes the parts---such as stored properties, collection elements,
tuple elements, or the active enumeration case---that make up a
particular instance. May also supply a "display style" property that
suggests how this structure might be rendered.
The properties id
(int
) and isItTrue
(bool
) are available to instances of MirrorMe
, but only as computed properties, as MirrorMe
does not implement these as stored properties, but rather, make use of the default implementation of them as computed properties from extension SomeProtocol where Self: SomeClass { ... }
. Hence, the computed properties id
and isItTrue
of MirrorMe
are not contained in the sub-structure representation of MirrorMe
instances, as provided by runtime introspection using Mirror
.
We can verify this clearly in a more minimal example:
class Foo {
// a stored property
let representedInIntrospection = 0
// a computed property
var notRepresented: Int { return representedInIntrospection }
}
Mirror(reflecting: Foo())
.children
.forEach { print($0.label, $0.value) }
/* Optional("representedInIntrospection") 0 */
To summarize: properties blueprinted in a protocol, with or without an associated default implementation, can never be stored properties on their own (default implementations of blueprinted properties may naturally only contain computed properties). This means that the only properties that are explicitly declared as stored properties in the class/struct that conforms to your protocol will show up when applying runtime introspection of an instance of such a class/struct.
Finally, you never mention the reason as for why you want a dictionary of the stored properties of a class instance, but take care if making use of this a production purpose. Generally, runtime introspection in a type safe language as Swift should only be used for diagnostics and debugging, even if it allows to be used in runtime hacks (e.g. with KVO for classes inheriting from NSObject
).
Swift Mirror API - Which protocols an object conforms to
Not possible at all in Swift. Swift reflection is a very limited affair. If you are willing to bridge your class into ObjC, you can use the ObjC Runtime functions to get what you want:
@objc protocol ProtocolA {}
@objc protocol ProtocolB {}
@objc protocol ProtocolC {}
class User : NSObject, ProtocolA, ProtocolC {}
var count: UInt32 = 0
let protocols = class_copyProtocolList(User.self, &count)
for i in 0..<Int(count) {
let cname = protocol_getName(protocols[i])
let name = String.fromCString(cname)
print(name)
}
Each of your protocol must be prefixed with @objc
and your class must inherit from NSObject
.
How can I check if a property has been set using Swift reflection?
I used @ebluehands technique of reflecting the Any
value to modify the original function. It cycles through the properties with an initial mirror, then reflects each one individually using displayStyle
to determine if the property is optional.
func allPropertiesHaveValues(obj: AnyObject) -> Bool {
let mirror = Mirror(reflecting: obj)
for child in mirror.children {
let value: Any = child.value
let subMirror = Mirror(reflecting: value)
if subMirror.displayStyle == .Optional {
if subMirror.children.count == 0 {
return false
}
}
}
return true
}
swift reflections: how to construct a new struct instance based on reflections?
You don't need reflection
and AableError
.
First of all lets add an init
to your protocol
protocol Aable {
var name: String { get }
init(name:String)
}
Now you want a +
operator where:
- both params conform to the protocol
Aable
- the params have the same type
- the return type is the same of the params
You can define this constraints with generics
func +<T:Aable>(left: T, right: T) -> T {
return T(name:left.name + right.name)
}
Now the check is performed at compile time so there's no need of the throws
. The compiler will make sure the used values do have the proper type.
Test #1
struct Box:Aable {
let name:String
}
let amazon = Box(name: "Amazon")
let apple = Box(name: "Apple")
let res = amazon + apple
res.name // "AmazonApple"
Test #2
struct Box:Aable {
let name:String
}
struct Box:Aable {
let name:String
}
struct Bottle:Aable {
let name:String
}
let box = Box(name: "Amazon")
let bottle = Bottle(name: "Water")
box + bottle
// ^ compile error
Swift Protocol with Variadic property
Is it not possible to create a Variadic property within a Protocol?
It is not possible, but this is just one reflection of a larger fact, namely, that a variadic is not a type. You are trying here to say products
is of type Variadic ProductModel. But there is no such type. No variable ever can be declared as being of that type; it isn't just protocols.
The only place variadic notation may appear is as a parameter type in an actual func
declaration, but then it is just a notation, not a type. It is a way of saying that the function can take a series of the actual type (Double, in your example from the docs).
So, if your protocol wants to declare a method with a parameter that's a variadic, fine. But the idea of a variable of variadic type is meaningless.
So just declare that the type of your variable is [ProductModel]
. That is how you say "some unknown number of ProductModel objects". And that's all that variadic notation means anyway, really, since the parameter is received inside the function body as an array.
Swift: Failed to assign value to a property of protocol?
You have to define the protocol as a class
protocol:
protocol ValueProvider : class {
var value: String {get set}
}
Then
var value: String {
get { return v.value }
set { v.value = newValue }
}
compiles and works as expected (i.e. assigns the new value to the
object referenced by v1
if v1 != nil
, and to the object
referenced by v2
otherwise).
v
is a read-only computed property of the type ValueProvider
.
By defining the protocol as a class protocol the compiler knows
that v
is a reference type, and therefore its v.value
property can be modified even if the reference itself is a constant.
Your initial code example works because there the v
property has
the type A
which is a reference type.
And your workaround
set {
var tmp = v1 ?? v2
tmp.value = newValue
}
works because (read-write) properties of variables can be set in
any case (value type or reference type).
Does Swift support reflection?
Looks like there's the start of some reflection support:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
From mchambers gist, here:
https://gist.github.com/mchambers/fb9da554898dae3e54f2
Related Topics
Nsattributedstring Boundingrect Returns Wrong Height
Osx/Swift: Call Function at a Specific Date/Time
Swift: Draw a Semi-Sphere in Mkmapview
Exc_Badinstruction When Computing a Hash Value
Cloudkit: How to Access Main User's Attributes
How to Update User Interface on Core Data
Choppy Animation Swiftui Nested Views
Dynamic UIcollectionviewcell Width with Respect to Frame Width and Aspect Ratio
How to Get The Range of The First Line in a String
Cllocationmanager and Tvos - Requestwheninuseauthorization() Not Prompting
Query Value Between Two Other Values in Firebase
How to Remove The Fading Animation on .Ondelete Swiftui
Creating Decoration View as Custom Column in UIcollection View
How to Name File Stored to Files App via Uactivityviewcontroller
How to Show Cluster for Mkpolyline with Geojson Data View in iOS Swift
Get Out of Navigation Controller and Go Back to Tab Bar View