How to subscript a dictionary that is stored inside a dictionary in swift? - swift

let current_data: [String : Any] = ["table": "tasks", "data": ["title": title_of_task, "completed_by": date_of_task]]
if (!description_of_task.isEmpty){
current_data["data"]["description"] = description_of_task
}
I get the following error:
Value of type 'Any?' has no subscripts

As matt notes, you need to redesign current_data. It is possible to do what you're describing, but the code is extremely ugly, complicated, and fragile because all interactions with Any are ugly, complicated, and fragile. It seems unlikely that you mean "Any" here. Would it be reasonable for the value to be a UIViewController, or a CBPeripheral, or an array of NSTimers? If it would be a problem to pass any of those types, you don't mean "literally any type." You almost never mean that, so you should almost never use Any.
To answer the question as asked, the code would be:
if (!description_of_task.isEmpty) {
if var data = current_data["data"] as? [String: Any] {
data["description"] = description_of_task
current_data["data"] = data
}
}
Yes, that's horrible, and if there are any mistakes, it will quietly do nothing without giving you any errors.
You could, however, redesign this data type using structs:
struct Task {
var title: String
var completedBy: String
var description: String
}
struct Row {
var table: String
var data: Task
}
With that, the code is trivial:
var row = Row(table: "tasks",
data: Task(title: "title_of_task",
completedBy: "date_of_task",
description: ""))
// ...
if !descriptionOfTask.isEmpty {
row.data.description = descriptionOfTask
}

Related

Why does return <expr> work when let var = <expr>; return var give an error that it can't convert the type

I have the following code, which compiles & works fine:
import RealmSwift
struct Bucket: Codable, Identifiable {
var id: UUID
var title: String
init() {
self.id = UUID()
self.title = "new bucket"
}
init(title: String) {
self.id = UUID()
self.title = title
}
init(id: UUID, title: String) {
self.id = id
self.title = title
}
}
class RealmBucket : Object {
#Persisted var id : UUID
#Persisted var title : String
convenience init(_ id: UUID, _ title: String) {
self.init()
self.id = id
self.title = title
}
}
func loadBuckets() -> [Bucket] {
let realm = try! Realm()
let realmBuckets = realm.objects(RealmBucket.self)
return realmBuckets.map { Bucket(id: $0.id, title: $0.title) }
}
but if I change the loadBuckets() function to:
func loadBuckets() -> [Bucket] {
let realm = try! Realm()
let realmBuckets = realm.objects(RealmBucket.self)
let result = realmBuckets.map { Bucket(id: $0.id, title: $0.title) }
return result
}
(just the last line changed)
I get the error:
Cannot convert return expression of type 'LazyMapSequence<Results<RealmBucket>, Bucket>' to return type '[Bucket]'
If I change the let line to be:
let result : [Bucket] = realmBuckets.map { Bucket(id: $0.id, title: $0.title) }
then it works again.
I can think of a couple possible explanations for the behavior, but they all seem to point to a compiler bug, or language deficiency, and I'm guessing that perhaps there is some language feature I'm unaware of.
Does anyone know why the compiler is able to automatically convert the LazyMapSequence in the case of the return value being a variable, when it clearly knows the type of the variable given the error it is giving me. I'm relatively new to Swift, and hoping to learn something from this.
Based on the current answers, my assumption is that it is just a slightly different case in the compiler code to convert the variable versus a method call, so it's really just a compiler deficiency, and likely to not exist down the road. In any case, it's easy enough to work around, it just struck me as odd.
You have to explicitly define the return type of map function, when you use shorthand closure syntax, probably that is the reason.
A “return” statement knows the type it has to return, so if applies that knowledge when the right hand side is evaluated, and can often convert that result to the correct type.
A let statement with no type means the compiler doesn’t know which type is needed. So the right hand side can be evaluated differently.

How can I implement a class structure that allows to an instance of a subclass to change to an instance of another subclass of the same class

I'm trying an item object that can be a note (just a string of text as property) or a task, so having a status, priority,a due date, etc. etc. as additional properties.
It would be possible transforming at runtime a note item in a task item and vice-versa.
I'm thinking how to implement this, I started defining a class structure having "item" as principal class and two subclasses (note and task) but I can't understand how managing the transition between the two subclasses
Can you help me?
This is not possible in Swift, at least not in any way that you'd use as a general tool. (It is possible in ObjC via isa-swizzling, and that can be bridged into Swift, but even in ObjC you'd never want to use it for this kind of problem. It's a very tricky tool, not a general purpose solution to types.)
Instead of complex class substitution, you want to redesign this. There are several approaches. You can just convert types (see the init(copying:) methods):
protocol Item {
var id: UUID { get }
var name: String { get set }
var contents: String { get set }
}
struct Note: Item {
let id: UUID
var name: String
var contents: String
init(copying item: Item) {
self.id = item.id
self.name = item.name
self.contents = item.contents
}
}
struct Task: Item {
let id: UUID
var name: String
var contents: String
var complete: Bool = false
var dueDate: DateComponents?
init(copying item: Item) {
self.id = item.id
self.name = item.name
self.contents = item.contents
}
}
Or, you can separate out additional properties and swap them (this approach is ideal if Item is a class, but I'd highly recommend trying to make Item a struct).
protocol ItemProperties{}
struct Item {
let id: UUID
var name: String
var contents: String
var properties: ItemProperties
}
// No additional properties for notes
struct Note: ItemProperties {}
struct Task: ItemProperties {
var complete: Bool = false
var dueDate: DateComponents?
}
var item = Item(id: UUID(), name: "", contents: "", properties: Note())
// convert to task
item.properties = Task(complete: false, dueDate: nil)
// Convert back to note
item.properties = Note()
That said, if you only have Tasks and Notes, I'd avoid overthinking this until you have a clear sense of what you'd add in the future. I'd consider just a simple struct with a type enum:
enum ItemType {
case note
case task(complete: Bool, due: DateComponents)
}
struct Item {
let id: UUID
var name: String
var contents: String
var type: ItemType
}
You can access these values using switch or if case let:
switch testItem2.type {
case let .task(complete: complete, due: due):
// Handle complete and due
break
case .note:
break
}
if case let .task(complete: complete, due: due) = testItem2.type {
// Handle complete or due
}
Sometimes it's convenient to create optional methods:
extension Item {
var complete: Bool? {
if case let .task(complete: complete, due: _) = type {
return complete
}
return nil
}
}
if let complete = testItem2.complete, complete {
// If this is a task and complete
}
The syntax around enums is sometimes a little clunky. If you have more than a couple of properties for the associated value, I highly recommend wrapping them up in a struct:
enum ItemType {
case note
case task(TaskProperties)
}
struct TaskProperties {
var complete: Bool
...
}
Barring a few tricks used in Objective C, a Swift instance can’t change it’s type at runtime. For one, different instances have different sizes, so there’s no good way to really make that work.
What you’re reaching for is something similar to SmallTalk’s become: message, which you can send to an object in order to get all references to it, program-wide, to be replaced with a reference to some other object instead. It’s cool, but leads to some confusing designs, and has some pretty brutal performance implications. You don’t really want this.
The exact best solution would depend on your specific use case. You haven’t provided much detail. The obvious/simple option is for each subclass to have an initializer that lets you create e.g. a new note from a task.
However, this won’t automatically update all references to the old note to point to the new task. If that’s something you need, you would need to add a layer of indirection yourself, where all item references point to items (which Item no longer has any subclasses), which themselves contain ItemDetails (or something like that) which are subclassed by NoteDetails and TaskDetails. Within the Item, the details can be switched back and forth between being a note or being a task, while all outstanding references to the wrapping item remain valid.
An alternative approach is by using a mixed design, of both structs and enums:
enum Item {
case note(Note)
case task(Task)
}
struct Note {
var text: String
}
struct Task {
var title: String
var status: Status
var priority: Priority
var dueDate: Date?
// ... other props
}
Switching between Note and Task would then be a simple matter of replacing self within the enum:
extension Task {
init(note: Note) {
self.init(title: note.text, status: .pending, priority: .low, dueDate: nil, ...)
}
}
extension Item {
mutating func convertToTask() {
guard case let .note(note) = self else {
// already a task, do nothing
// alternatively, you can throw an error
return
}
self = .task(Task(note: note))
}
}
// look, I have a `Note`
var item: Item = .note(Note(text: "something to do"))
// but now I have a `Task` :)
item.convertToTask()

How do I reference fields in a self defined NSObject?

Looking for assistance since I am missing something! I have defined a new object called "User".
class User: NSObject {
var userID: String!
var fullname: String!
var imagePath: String!
}
Now I want to iterate through each object one at a time checking the values of some of the fields.
func retrieveUsers() {
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot: DataSnapshot) in
let users = snapshot.value as! [String: AnyObject]
self.user.removeAll()
for (key,value) in users {
// HOW DO I REFERENCE A FIELD IN THE USER OBJECT
}
}
Keep in mind that in your code, your users object is of type [String:AnyObject] since you're grabbing it from a database (Firebase?).
So, you have an untyped Dictionary to deal with.
You can reference fields on the dictionary by doing users[key] where key is a String.
Judging by your naming of variables, it looks like you're expecting users to be an array rather than a dictionary, but then you're casting it as a dictionary. Without knowing your database schema it's hard to say what's actually happening.
But, you most likely want to actually turn your [String:AnyObject] into your actual data type. There are a number of approaches to this, but you may have to write your own decoder.
You may want to add more information about what database you're actually using.
Update: Including an example method for turning your dictionary into your object:
class User: NSObject {
var userID: String
var fullname: String
var imagePath: String
required init(withDictionary dict : [String: AnyObject]) {
userID = (dict["userID"] as? String) ?? ""
fullname = (dict["fullname"] as? String) ?? ""
imagePath = (dict["imagePath"] as? String) ?? ""
}
}
Note that I'm not handling failures -- just putting in empty strings.
You can also look into storing making your model Codable compliant and try to convert in and out of JSON. See: How can I use Swift’s Codable to encode into a dictionary?

Extending a constrained protocol for an array argument is not possible

I'm going to explain it by an example. We have a protocol for force having firstName and lastName like:
protocol ProfileRepresentable {
var firstName: String { get }
var lastName: String { get }
}
the type we are going to use have these two, but in an optional form:
struct Profile {
var firstName: String?
var lastName: String?
}
so after conforming to the ProfileRepresentable, we will extend the ProfileRepresentable and try to return the value and a default one for nil state:
extension Profile: ProfileRepresentable { }
extension ProfileRepresentable where Self == Profile {
var firstName: String { self.firstName ?? "NoFirstName" }
var lastName: String { self.lastName ?? "NoLastName" }
}
So far so good
Now there is a similar flow for a list of Profiles.
protocol ProfilerRepresentable {
var profiles: [ProfileRepresentable] { get }
}
struct Profiler {
var profiles: [Profile]
}
First issue
conforming to ProfilerRepresentable does NOT automatically done the implementation as expected (since Profile already conforms to ProfileRepresentable)
extension Profiler: ProfilerRepresentable { }
Second Issue
Following the previous pattern, extending ProfilerRepresentable is not working as expected and it raises a warning:
⚠️ All paths through this function will call itself
extension ProfilerRepresentable where Self == Profiler {
var profiles: [ProfileRepresentable] { self.profiles }
}
How can I achieve the goal for arrays by the way ?
Here is possible solution. Tested with Xcode 12 / swift 5.3
protocol ProfilerRepresentable {
associatedtype T:ProfileRepresentable
var profiles: [T] { get }
}
extension Profiler: ProfilerRepresentable { }
struct Profiler {
var profiles: [Profile]
}
[Profile] is not a subtype of [ProfileRepresentable]. (See Swift Generics & Upcasting for a related but distinct version of this question.) It can be converted through a compiler-provided copying step when passed as a parameter or assigned to a variable, but this is provided as a special-case for those very common uses. It doesn't apply generally.
How you should address this depends on what precisely you want to do with this type.
If you have an algorithm that relies on ProfilerRepresentable, then Asperi's solution is ideal and what I recommend. But going that way won't allow you to create a variable of type ProfileRepresentable or put ProfileRepresentable in an Array.
If you need variables or arrays of ProfilerRepresentable, then you should ask yourself what these protocols are really doing. What algorithms rely on these protocols, and what other reasonable implementations of ProfileRepresentable really make sense? In many cases, ProfileRepresentable should just be replaced with a simple Profile struct, and then have different init methods for creating it in different contexts. (This is what I recommend if your real problem looks a lot like your example, and Asperi's answer doesn't work for you.)
Ultimately you can create type erasers (AnyProfile), but I suggest exploring all other options (particularly redesigning how you do composition) first. Type erasers are perfect if your goal is to erase a complicated or private type (AnyPublisher), but that generally isn't what people mean when they reach for them.
But designing this requires knowing a more concrete goal. There is no general answer that universally applies.
Looking at your comments, there no problem with having multiple types for the same entity if they represent different things. Structs are values. It's fine to have both Double and Float types, even though every Float can also be represented as a Double. So in your case it looks like you just want Profile and PartialProfile structs, and an init that lets you convert one to the other.
struct Profile {
var firstName: String
var lastName: String
}
struct PartialProfile {
var firstName: String?
var lastName: String?
}
extension Profile {
init(_ partial: PartialProfile) {
self.firstName = partial.firstName ?? "NoFirstName"
self.lastName = partial.lastName ?? "NoLastName"
}
}
extension PartialProfile {
init(_ profile: Profile) {
self.firstName = profile.firstName
self.lastName = profile.lastName
}
}
It's possible that you have a lot of these, so this could get a bit tedious. There are many ways to deal with that depending on exactly the problem you're solving. (I recommend starting by writing concrete code, even if it causes a lot of duplication, and then seeing how to remove that duplication.)
One tool that could be useful would be Partial<Wrapped> (inspired by TypeScript) that would create an "optional" version of any non-optional struct:
#dynamicMemberLookup
struct Partial<Wrapped> {
private var storage: [PartialKeyPath<Wrapped>: Any] = [:]
subscript<T>(dynamicMember member: KeyPath<Wrapped, T>) -> T? {
get { storage[member] as! T? }
set { storage[member] = newValue }
}
}
struct Profile {
var firstName: String
var lastName: String
var age: Int
}
var p = Partial<Profile>()
p.firstName = "Bob"
p.firstName // "Bob"
p.age // nil
And a similar converter:
extension Profile {
init(_ partial: Partial<Profile>) {
self.firstName = partial.firstName ?? "NoFirstName"
self.lastName = partial.lastName ?? "NoLastName"
self.age = partial.age ?? 0
}
}
Now moving on to your Array problem, switching between these is just a map.
var partials: [Partial<Profile>] = ...
let profiles = partials.map(Profile.init)
(Of course you could create an Array extension to make this a method like .asWrapped() if it were convenient.)
The other direction is slightly tedious in the simplest approach:
extension Partial where Wrapped == Profile {
init(_ profile: Profile) {
self.init()
self.firstName = profile.firstName
self.lastName = profile.lastName
self.age = profile.age
}
}
If there were a lot of types, it might be worth it to make Partial a little more complicated so you could avoid this. Here's one approach that allows Partial to still be mutable (which I expect would be valuable) while also allowing it to be trivially mapped from the wrapped instances.
#dynamicMemberLookup
struct Partial<Wrapped> {
private var storage: [PartialKeyPath<Wrapped>: Any] = [:]
private var wrapped: Wrapped?
subscript<T>(dynamicMember member: KeyPath<Wrapped, T>) -> T? {
get { storage[member] as! T? ?? wrapped?[keyPath: member] }
set { storage[member] = newValue }
}
}
extension Partial {
init(_ wrapped: Wrapped) {
self.init()
self.wrapped = wrapped
}
}
I don't love this solution; it has a weird quirk where partial.key = nil doesn't work to clear a value. But I don't have a nice fix until we get KeyPathIterable. But there are some other routes you could take depending on your precise problem. And of course things can be simpler if Partial isn't mutable.
The point is that there's no need for protocols here. Just values and structs, and convert between them when you need to. Dig into #dynamicMemberLookup. If your problems are very dynamic, then you may just want more dynamic types.

Type *My Custom Class* has no subscript members

This is a question I was just about to post my finished answer to, but it seems that the author just at that moment deleted the question, possibly as the only reply was a comment saying it was not possible. I myself found the technical aspect of the question somewhat interesting, so I'm adding the same question and the answer here, in case someone else finds this of interest.
Feel free to edit this post/topic as well as its answer. Also, I've looked in the meta for guidelines regarding re-posting a deleted question in this fashion, however without finding any explicit non-advice for doing so. Please let me know if I'm in the wrong here.
(Original question from SO user Jaime)
Type My Custom Class has no subscript members
I'm trying to do some javascript-esque code and it's blowing up.
class Product {
var name : String!
var type: String!
var description: String!
var taste: String!
var picturePath: String!
var pairings: [String]
var similar: [String]
init(dict: Dictionary<String, AnyObject>) {
let props = ["name", "type", "description", "taste", "pairings", "similar"]
for prop in props {
self[prop] = dict[prop]
}
}
}
Is there a way to do what I'm trying to do here, or do I have to manually initialize all the properties of the class e.g.
if let title = dict["name"] as? String {
self.title = title
}
//... and so on
First of all: as Alex wrote in his comment to the original question, this should generally be avoided.
It feels to weird to answer a question with "no"; even if it is
possible, it would either not be type-safe, or it would require so
much boilerplate that you'd be better off just writing the initializer
by hand. Swift is very often not conducive to writing Javascript-esque
code, since it's staticly, strongly typed.
Anyway, you can do this with the help of Mirror (reflecting upon self) and a tidy bit of obj-c; letting your class inherit from NSObject
class Product : NSObject {
var varDump: AnyObject?
var name : String?
var type: String?
// ...
init(dict: Dictionary<String, AnyObject>) {
super.init()
let a = Mirror(reflecting: self).children.filter { $0.label != nil }
for b in a {
self.setValue(dict[(b.label ?? "")], forKey: (b.label ?? "varDump"))
}
}
}
var propertyInit = [String:AnyObject]()
propertyInit["name"] = "John"
propertyInit["type"] = "Human"
var a = Product(dict: propertyInit)
print(a.name ?? "Not initalized") // John
print(a.type ?? "Not initalized") // Human
In addition to the NSObject inheritance, you see that all properties that you wish to initialize in this fashion have been set to optional above. This is naturally because swift cannot know until runtime if you actually initialize these properties or not, hence yielding a compile time error if you mark them as non-optional.
Finally, again note what Alex wrote in his comment (quoted), and take this answer as a technique to do something, but not actually something that is to be recommended if you want to follow common Swift convention. This code will easily break at runtime if you're not very careful in you dict initialization, as you fully loose type safety.