I'm debugging my program to check if the value of a property is correctly set. I put a breakpoint in this function:
func showContent(data: Any) -> UIView {
// breakpoint here
var contentView = UIView()
if let image = data as? UIImage {
let imageView = UIImageView()
imageView.image = image
contentView = imageView
}
if let text = data as? String {
let label = UILabel()
label.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
label.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
label.text = text
contentView = label
}
return contentView
}
The value passed to this function is from a view controller:
override func viewDidLoad() {
calcGroupFamiliarity()
flashCardView.linkedMemory = Memory(masteryLevel: 1, algorithm: Algorithm.algorithm1.chooseAlgorithm(), forgetRatio: 0, lastStudyTime: Date(), front: #imageLiteral(resourceName: "Ideas-Blue"), back: #imageLiteral(resourceName: "Ideas-Yellow"))
}
As you can see, both the front
and the back
are images, however, in the debugger, they both appeared as some payload_data
, while the data type of other values such as masteryLevel
and algorithm
are correct:
Can somebody explain what that means? And what should I do to pass the normal image data instead?
Update:
This is Memory
class:
class Memory: NSObject, NSCoding {
var masteryLevel: Int
var algorithm: [Int: Double]
var forgetRatio: Int
var lastStudyTime: Date
var strength: Double = 0
var front: Any
var back: Any
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask)[0]
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("Memory")
init(masteryLevel: Int, algorithm: [Int: Double], forgetRatio: Int, lastStudyTime: Date, front: Any, back: Any){
self.masteryLevel = masteryLevel
self.algorithm = algorithm
self.forgetRatio = forgetRatio
self.lastStudyTime = lastStudyTime
self.front = front
self.back = back
}
...
}
This is a detail of how Swift implements the Any
type. Given that Swift can't know beforehand what you are putting into e.g. front
, it needs to store a pointer to that object (in payload_data_0
) as well as a pointer to metadata about the stored object's type (in instance_type
). As far as I know, payload_data_1
and payload_data_2
are there as an optimization so that Swift can store up to 24-byte large structs in place rather than having to put them in a wrapper object that needs to be stored in a separate heap location.
So, to answer your question: This is neither a bug in Swift, nor an error on your side. Your data gets stored and accessed in the right way. If you would prefer to inspect front
more easily while debugging, try
(lldb) po front
in the debugger. Alternatively, change front
's type to e.g. UIImage?
. If that is not possible, you could declare a protocol
protocol MemoryStoreable: class { }
and extend every type that needs to be stored in those fields like so:
extension UIImage: MemoryStoreable { }
and declare the variable as
var front: MemoryStoreable?
Note that MemoryStoreable
is restricted to classes, as otherwise a protocol witness would need to be stored (which is again implemented similarly to the Any
field you observed).
Another alternative would be, if you know you'll store e.g. only images and strings in front
, to use an enum:
enum MemoryStoreable {
case `string`(String)
case image(UIImage)
}
var front: MemoryStoreable?
That will still require at least 25 bytes of storage in your object (possibly 32 due to memory alignment constraints), though, as that's the size of the String
struct.
For more details, see e.g. https://mikeash.com/pyblog/friday-qa-2014-08-01-exploring-swift-memory-layout-part-ii.html.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With