missing argument for parameter in call in tuple [duplicate] - swift

This question already has answers here:
How to append a tuple to an array object in Swift code? [duplicate]
(3 answers)
Closed 7 years ago.
So I am working on a menu-type class and for some reason I am getting the error: "Missing argument for parameter 'dishes' in call"
Here is the code:
class Meal {
var nameOfMeal: String
var menu : [(sectionName: String, dishes: [Dish])]
var hours: String
init(nameOfMeal: String, menuIDs: [(sectionName: String, dishIDs: [String])], hours: String) {
self.nameOfMeal = nameOfMeal
setMenuFromIDs(menuIDs)
self.hours = hours
}
func setMenuFromIDs(menuIDs: [(sectionName: String, dishIDs: [String])]){
menu = []
for menuSection in menuIDs {
var loadedDishes = CoreDataUtility.loadArrayOfDishesFromIDs(menuSection.dishIDs)
menu.append((sectionName: menuSection.sectionName, dishes: loadedDishes))
}
}
}
The error is on the menu.append((sectionName: menuSection.sectionName....))
I have checked the type of menu, loadedDishes, I've separated the argument in menu.append and checked it's type and they're all appearing as they should. None are optionals. I've removed the sectionName and dishes label from the tuple but the error still mysteriously appears.
Can anyone please help me figure out why?
Thanks!

As Nate Cook said here:
… don't do this. Tuples are designed for temporary use and will miss out on a lot of Swift's strengths (compiler optimizations, etc.) …
Based on that answer, I rewrote your code as:
typealias MyTuple = (sectionName: String, dishes:[Dish])
class Meal {
var nameOfMeal: String
var menu : [MyTuple]
var hours: String
init(nameOfMeal: String, menuIDs: [(sectionName: String, dishIDs: [String])], hours: String) {
self.nameOfMeal = nameOfMeal
self.hours = hours
self.menu = [("", [Dish]())]
setMenuFromIDs(menuIDs)
}
func setMenuFromIDs(menuIDs: [(sectionName: String, dishIDs: [String])]){
menu = []
for menuSection in menuIDs {
var loadedDishes = CoreDataUtility.loadArrayOfDishesFromIDs(menuSection.dishIDs)
menu.append((menuSection.sectionName, loadedDishes))
}
}
}
… and it now compiles!
Note that I also moved the line setMenuFromIDs(menuIDs) to the bottom of the init function and initialised your menu property (to avoid another compiler warning, of using self before its initialized).

Related

How can I access private property outside that class in Swift? [duplicate]

This question already has answers here:
Read-Only properties
(3 answers)
Closed 9 months ago.
Here I have a class and make its properties private to prevent from modifications by accident.
class Article {
private var lineIndex: [Int] = []
private var text: [String] = []
....
}
I know I can write a function like func text(_ index: Int) -> String to get its value at index. But when I call it, article1.text(2) would be weird. Because it's less clear to indicate 2 is an index than what an array does like article1.text[2]. So can I use getter or something else instead, while keeping the clear syntax like text[2]. It couldn't be better if you can offer some examples.
You can use one of these ways:
with private(set), which allows editable inside the class:
class Article {
private(set) var text: [String] = []
...
}
with get only computed property (this is the same like your get function)
class Article {
var _text: [String] {
return text
}
}

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.

Get a Swift class's property name as a String [duplicate]

This question already has answers here:
Get a Swift Variable's Actual Name as String
(7 answers)
Closed 5 years ago.
How do I get the property name as a string?
class Person {
var firstName: String
var lastName: String
var downloading: Bool
func excludePropertiesFromCloud() -> [String] {
return //here I want to return ["downloading"]
}
}
I would like to avoid having to type return ["downloading"] to prevent errors if the name of the variable changes later on.
To get the class name you can use String(describing: Person.self), so I am looking at something similar for properties.
Note:
Although the title of the question is very similar to Get a Swift Variable's Actual Name as String, it is clear that the accepted answer in the original question returns the value of the property and does not answer this straightforward question. The original question is the first to come up on any google search with "Swift get property name", and the answer answers something else, as pointed to by #MarqueIV. This is why I created this question
If you are ok with making your properties #objc you can get the property name like so:
class Person {
#objc var firstName: String
var lastName: String
var downloading: Bool
func excludePropertiesFromCloud() -> [String] {
return [#keyPath(firstName)]
}
}

Expected declaration when adding values to a Swift dictionary [duplicate]

This question already has answers here:
swift compiler shows Expected declaration error? [duplicate]
(3 answers)
Expected Declaration Error using Swift
(1 answer)
Closed 5 years ago.
I get the error "expected declaration" on the last line when trying to add values to the dictionary tablesBooked.
class BookingSystem {
var tablesBooked = Dictionary<Int, String>()
var table = Table(tableID: 1 , tableCapacity: 2, status: "A")
var bookings = [Booking]()
tablesBooked.setValue(table.status, forKey: table.tableID)
}
You get this error because your line setValue cannot just live here inside your class without being inside a method. Of course here it really depends on what (and how) you want to accomplish, but you could put it in the init() method of your BookingSystem class, or you could build your own custom init().
Here is how it would look like:
import Foundation
class Booking {
// Some interesting things here
}
class Table : NSObject {
// MARK: Properties
var tableID: Int
var tableCapacity: Int
var status: String
// MARK: Initializers
init(tableID: Int, tableCapacity: Int, status: String) {
self.tableID = tableID
self.tableCapacity = tableCapacity
self.status = status
}
}
class BookingSystem {
// MARK: Properties
var tablesBooked = [Int: String]()
var table = Table(tableID: 1 , tableCapacity: 2, status: "A")
var bookings = [Booking]()
// MARK: Initializers
init() {
// I am not sure what you are trying to do here, but anyway you should add it in a custom method or your init. If I were to use the code in your example, you would add this here:
tablesBooked[table.tableID] = table.status
}
// ...
}
I added the Table class here on purpose, just to show you an example on how to create your own custom init.
Also, another thing worth mentioning here is that Swift Dictionaries don't have a setValue:forKey: method. Instead, to add an object to your Dictionary, you should use:
yourDictionnary["yourKey"] = yourValue
Hope it helps, and if you have any questions just feel free asking :)
Use init method:
class BookingSystem {
var tablesBooked = Dictionary<Int, String>()
var table = Table(tableID: 1 , tableCapacity: 2, status: "A")
var bookings = [Booking]()
init() {
tablesBooked.setValue(table.status, forKey: table.tableID)
}
}

Swift class: reference cycle

When I run the below program, it produces segmentation fault. Can you please help me figure out why? Thanks
class Animal:NSObject{
var name:String!
var age:UInt!
weak var spouse:Animal?
init(name:String,age:UInt){
self.name=name
self.age=age
}
func description() ->String{ //to become printable
return "name= \(name) and age=\(age) spouse=\(spouse)"
}
}
let dog=Animal(name:"Lucky",age:3)
let cat=Animal(name:"Branson",age:4)
dog.spouse=cat
cat.spouse=dog //It doesnt crash if I comment this line out
println(dog)
The problem is infinite recursion in your printing. Once you set up the full cycle, to print an animal, you print its spouse, which prints its spouse, which print’s its spouse etc. forever until you run out of stack space and crash.
You need to break that by printing out an animal’s spouse without calling the full print of that animal, something like this:
class Animal: NSObject {
// you should avoid using implicitly unwrapped optionals
// unless you absolutely have to for a specific reason that
// doesn’t appear to apply here (so remove the !s)
var name: String
var age: UInt
weak var spouse: Animal?
init(name: String, age: UInt) {
self.name = name
self.age = age
}
}
// to make something printable, you need to conform
// to the Printable protocol
extension Animal: Printable {
// And make description is a var rather than a function
override var description: String {
let spousal_status = spouse?.name ?? "None"
return "name=\(name) and age=\(age), spouse=\(spousal_status)"
}
}
let dog = Animal(name: "Lucky", age: 3)
let cat = Animal(name: "Branson", age: 4)
dog.spouse = cat
dog.description
cat.spouse = dog
println(dog) // Prints name=Lucky and age=3, spouse=Branson
Note, you have to implement Printable fully with the protocol and var to avoid this problem, otherwise you’ll get the default implementation, which will still experience the issue.
btw, Swift style convention is to put spaces between things like =, ->, before { etc. (and in fact you can occasionally cause compilation problems if you don’t). Jury’s still out on a: b vs a:b though I find the latter a bit harder to read.
Your code triggers a stack overflow. The description method contains the spouse description, which will in turn trigger the description of its spouse and so on in a never ending cycle. Try this:
func description() -> String {
return "name= \(name) and age=\(age) spouse=\(spouse?.name)"
}