قالب وردپرس درنا توس
Home / IOS Development / Mirror / CustomReflectable / CustomLeafReflectable

Mirror / CustomReflectable / CustomLeafReflectable



Reflection in Swift is a limited affair,
provides read-only access to information about objects.
In fact, this functionality can be better described as
introspection rather than reflection.

But can you really blame them for going with that terminology?

"Introspection" is such a flourishing and acoustically unpleasant word
compared to "reflection".
And how can anyone pass the nominal sludge dunk off
call the type that is responsible for reflecting the value of an object a Mirror ?
What equivalent analogy can we convey for the introspection?
struct Long Dark Tea Time Or The Soul ?
(As if we had no better things to do than
ask our swift code about the meaning of even )

Without further ado,
let's take a look at the inner work of how Swift is exposed
The one of our own code:
Mirror Custom Reflectable and Custom Leaf Reflectable .


Swift provides a standard reflection ] or structured view,
for each item.
This view is used by playgrounds
(unless a custom description is provided),
and also serves as a refund when describing objects
which does not match
Custom String Convertible or Custom Debug String Convertible Protocols.

You can customize how instances of a type are reflected
by adopting the Custom Reflectable protocol
and implement the necessary custom Mirror property.

Property Custom Mirror Returns an Item Mirror
which is usually constructed by reflecting itself and
passes the properties you want to expose to the reflected interface.
Properties can be either
typed and passed in a dictionary
or unkeyed and passed in a matrix.
You can optionally set a screen style
to override standard for the type struct class tuple etc.);
if the type is a class,
You also have the option to adjust how ancestors are represented.

In accordance with CustomReflectable

To get a better understanding of how this looks like in practice,
Let's look at an example that involves the implementation of a data model
for the game chess:

A chess board consists of 64 squares,
shared in
8 rows (cold ranks ) and
8 columns (called files ).
A compact way to represent each place on a table
is 0x88 method,
The rank and file are encoded in 3 bits of each
munch
]

For simplicity, Rank and File are typical for UInt8
and use single-based indexes;
Typealias Rank = UInt8
typealias File = 1

9659013] uint8

struct Coordination : [19659015] equatable Hashable {
private la value : uint8

var rank [19659025]: Rank
return value >> 3 ) + 1
}

var file [19659025]:
return ( value & 0b00000111 [19659025]) + 1
}

: ] 1 8 ~ = Rank [19659017] && [1 9659044] 1 8 ~ = file )
itself . = (( Rank 1 ) << 3 ) + 1 )
}
}

If we were to construct a coordinate for b8 (rank 8, file "b" or 2)
default reflection would not be particularly helpful:

  la    b8    =    ChessBoard .     :    8     file :    2 ) 
  String  (  reflects :    b8 )    // ChessBoard .Coordinate (value: 57) 

57 in decimal equals 0111001 in binary,
or a value of 7 for rank and 1 for file,
which adds the index offset of 1 brings us to
grade 8 and file 2.

The default mirror is given for a structure
Includes each of the object's stored properties.
However, consumers of this API do not need to know
or even worry about implementation details about how this information is stored.
It is more important to reflect the programmatic surface of the type,
and we can use Custom Reflectable to do just that:

  extension    ChessBoard .                 

] customMirror : Mirror 19659040] : [

] : rank "file" : file ] } }

Instead of exposing the privately stored value the property,
Our custom mirror provides calculated rank and file properties.
The result: a much more useful representation
which reflects our understanding of the type:

  String  (  Reflecting :    b8 )    // ChessBoard.Coordinate (Rank: 8, File: 2) [19659172] ] Introspecting the Custom Mirror 

String (reflective :) initializes is a way that mirrors are used. But you can also get them directly through custom Mirror property to access the type of metatype and display style, ] . subjectType // ChessBoard.Coordinate.Type b8 . customMirror displayStyle // struct for children in b8 . customMirror . child children . ] ] ] ) ) ] ] ] ] ) }

Customize Display of a Custom Mirror

There are different shaped mirrors for each kind of Swift value,
each with its own special features.

For example,
The most important information about a class is its identity,
so the reflection contains only its fully qualified type name.
While a structure is about substance
giving up its name and values.

If you find this to be less than flattering for your particular type
You can change your appearance by entering a set value
to display style attribute in mirror initializes.

Here is a selection of what to expect
for each of the available display styles

[

]

]

] [Meldpå

19659025]: Mirror 19659028] : [ "rank" [19659025]: rank ] : file ])
displayStyle : < # displayStyle # > ]
}

Style Output
class Chess Board.Coordinate
struct Coordination (rank: 8, file: 2) [19659232] enum Coordinate (8)
optional 8
tuple (rank: 8, file: 2)
collection ] [8, 2]
set [19659233] {8, 2}
dictionary [rank: 8, file: 2]

Unlabeled Children

  Extension    ChessBoard .  :             

] unlabeledChildren : [ rank [19659025] file ] displayStyle : < # ] ] } }

    

Style Output
Class Chess Board.Coordinate
Struct ]
enum Coordinate (8)
optional [19659263]
tuple (8, 2)
collection [8, 2]
set set ] {8, 2}
dictionary [ 8, 2]

Reflection and Class hierarchies

Continuing with our chess example,
let's introduce a class by defining an abstract piece class
and subclasses for peasants, knights, bishops, rooks, queens and kings.
(For taste, let's add default values
enum Color : String [
black ] white
]

la color : Color
la location . Chessboard Coordinate

     : Color Place . Chessboard Coordinate [19659025]? = nil ) {
itself . color = color
itself . Location = Location
Condition (

Type ( to [19659025!]: Self ) = ] 19659025] [Pieces [Pieces] ]
}
]

class Bonde : Piece ] static stat la value = 1 }
class Knight : Piece { static la value = 3 } class Bishop : Piece { static la [19659032] } Class : Piece { Static la Value = 5 }
class Queen : Piece {[19659359] static la value = 9 [19659014]
class King : Piece {}

So far so abrupt.
Now let's use the same approach as before to define a custom mirror
(setting the display Style to struct
so that we get more reflective information than we would otherwise like for a class):

  extension    Piece :    CustomReflectable    {
      var    customMirror : [19659015]              [     :   : : : :   :    [ 19659025]    
          
         : :    location    ??    "N / A" ] 
                        displayStyle :  . [19659441] struct 
    ) 
    } 
} 

Let's see what happens if we try to reflect a new Knight item:

  la    knight    ]         color :      black     location .    b8 ) 

String [19659025] ( reflective : skip ]

] Piece ( color [19659025]: black location : [19659025]: 8 file : 2 ))

Hmm … that's not good.
What if we try to override it in an extension to Knight ?

] : [ "color" : color
"location" : location ] "N / A" ])
}
} //! Error: Overall declarations in extensions are not supported

No dice (to mix metaphors).

Let's look at three different options to make this work with classes.

Option 1: Observe CustomLeafReflectable

Swift actually provides something for just such a situation –
a protocol inheriting from Custom Reflectable
Leaf Reflectable
its reflections of subclasses will be suppressed
unless they explicitly override adapted Mirror and give their own Mirror .

Let's take a new look at our example from before,
Custom Leaf Reflectable
in our original statement:

  class    Piece :    CustomLeafReflectable    {
      // .. .   ]    customMirror :    Mirror    
          return    Mirror  (  reflective :    self ) [19659010] ] ] 
      ] 

] : Piece { // ... override var ]

[ : color "location" : location ?? "N / A" "value" ]: Knight value ] displayStyle .:. struct ) } } [196590101] Now When we are going to reflect our knight, We get the right kind -

Knight instead of Piece . String ( Reflects : Knight ) // Knight (Color: Piece.Color.black, Location: (Rank: 8, File: 2) , value: 3)

Unfortunately, this approach requires us to do the same
for each of the subclasses.
Before we suck it up and copy-paste the way to victory,
Let's consider our alternatives.

Option 2: Encode Type in Superclass Mirror

An Easier Option to Go Custom Leaf Reflectable Route
is to include the type of information as a child of the mirror
: CustomReflectable {
var customMirror : Mirror Mirror : [ ] "type" : type ( of : [19659030] ]
"color" : color
"location" : location ?? "N / ]
displayStyle . struct )
}
}

String ([19659065]] reflects : knight )
// Piece (type: Knight, color: black, location: (rank: 8, file: 2))

This approach is appealing
because it allows reflection to be hidden as a completion detail.
However, it can only work if subclasses are differentiated by behavior.
If a subclass adds saved members
or significantly different in other ways,
It will need a specialized representation.

Who puts the question:
Why do we use classes in the first place?

Option 3: Avoid classes completely

Truth be told,
We only introduced really classes here
as a good example of how to use Custom Leaf Reflectable .
And what we experienced is a little mess, right?
Ad hoc addition of value writes members for just some of the pieces
(kings do not have a value at bay because they are a winning state)?
An "abstract" base class crashing if you try to instantly
(for the current lack of a first-class language function)?
Yikes.
There are such things that give OOP a bad name.

We can alleviate almost all of these issues
by adopting a protocol-oriented approach as follows:

First, define a protocol for Piece
and a new protocol for encapsulating pieces that have value, called Valuable :

  Protocol    Piece    {
      Var    Color :    Color [19659028]] {   few  } 
      var    location .:?    Chess Board     Coordination     {    } 
} 

  Protocol    Value ~~ POS = TRUNC :    ]    {
      
                 ]      :    Int    {[19659031]]  } 
}    Then you define value types -
                      ]   ]    // ... 

  struct    Knight :    Pieces     Valid    [
      Static    la    ] :             =    3 

la color : Color

19659107] Coordinate ? } // ...

Although we can not match protocol by extension,
We can provide a standard implementation for the requirements
and declare adoption in extensions to each concrete Piece type.
As a bonus, Valuable can provide a specialized variant
which includes its value :

  extension    Piece    {
      var    customMirror :    Mirror    {
          return             :    [   "color" :    color  
                                   "location" [19659025] :    location    ??    "N / A" ] 
                        displayStyle .      struct ) 
    } [19659108]} [19659035]     

: [ "color" : color "location" : location [19659014] ?? "value" . ] displayStyle :. ] } ] // ... Extension Knight : CustomReflectable {} ] //. ..

Sets everything,
We get exactly the behavior we want
= ChessBoard . ] : 2 ) la jumps = Knight ( color ] [19659042] black location : b8 )

String ( reflective : springer ])
// Knight (color: black, placement: (rank: 8, file: 2))

Ultimately,
Custom Leaf Reflectable is given for the most part for compatibility with
The classic hierarchical types in Target C-frames like UIKit.
If you enter new code, you do not need to follow their footsteps.


When Swift first came out,
Meal C developers for a long time missed the dynamics offered by that time.
And – truth is told –
Truth be told, things were not all super great.
Programming in Swift can, at times,
Feels unnecessarily finite and limiting.
"If only we could swizzle …"
we wanted to grumble.

And maybe this is still the case for some of us some of the time,
but with swift 4,
Many of the most frustrating uses have been solved.

Codable is a better solution for JSON serialization
than it was available with dynamic introspection.
Codable can also provide mechanisms for fuzzing and fixtures
to sufficient initiative and clear developers.
Case The Iterable protocol fills another hole,
gives us a first-rate mechanism
to get an overview of the recording conditions.
In many ways,
Swift has sprung promise of dynamic programming,
APIs like Mirror generally do not need logging and debugging.

Having said that,
should you find the need for introspection,
you just know where to see.


Source link