I want to write a function that returns text and an integer inside an if statement in Swift - swift

I want to create a function that returns both text and integer. And I want to have an if loop inside this function. If the number of steps of the 1st user is more than the 2nd, the step difference of these two users and a text that says you are ahead should be returned.If the 2nd user has more steps than the 1st user, I want it to return a text saying that there is a difference in the number of steps between them and you are behind.
In my hand like this.
struct ActiveDuel{
let state: String
let user1StepCount: Int
let user2StepCount: Int
let user1Name: String
let user2Name: String
let user1Phote: String
let user2Phote: String
let stepDif: Int
let goldAmount: Int
let time: Int
let lastUpdateTime: Int
let startTime: Int
let docId: String
}
I created the code like this but it looks wrong and also doesn't contain text.
func DıfferenceStep(user1StepCount:Int , user2StepCount: Int ) -> Int{
if user1StepCount > user2StepCount {
let DıfferenceStepFunc = user1StepCount - user2StepCount
}else if user2StepCount > user1StepCount {
let DıfferenceFalseStep = user2StepCount - user1StepCount
}
}
I don't know how to use if statement inside functions and besides that I want it to return both integer and text.I would be glad if you help me in this regard.

Here is an example of your struct with a func inside it. You create the struct and then call the func on the struct instance.
struct ActiveDuel
{
var user1StepCount: Int = 0
var user2StepCount: Int = 0
var user1Name: String?
var user2Name: String?
func stepsDifference() -> Int
{
return abs(user1StepCount - user2StepCount)
}
}
let duel = ActiveDuel(user1StepCount: 30, user2StepCount: 5, user1Name: "Bill", user2Name: "Ted")
print(duel.stepsDifference())
I would consider making a Duelist struct and store each duelist's individual information in that instead of in the general ActiveDuel struct. Then you could have a Duel struct that had an active Bool property (true/false), and any number of Duelists (you could limit it to two).

Depending on how you use this it would be better to create 2 different computed properties in your ActiveDuell struct. One returning the difference in points and one returning a string that gives the information you want.
struct ActiveDuel{
let state: String
let user1StepCount: Int
let user2StepCount: Int
let user1Name: String
let user2Name: String
let user1Phote: String
let user2Phote: String
let stepDif: Int
let goldAmount: Int
let time: Int
let lastUpdateTime: Int
let startTime: Int
let docId: String
var pointDifference: Int{
// calculate the difference and make the result positive
abs(user1StepCount - user2StepCount)
}
var standings: String{
// if the difference is 0 the game is tied
if user1StepCount == user2StepCount{
return "you are tied"
} else {
// put the name of the leader and the points they lead in to the string
return "\(user1StepCount > user2StepCount ? user1Name : user2Name), you lead by \(pointDifference) points"
}
}
}
you can use it like this:
let activeDuel = ActiveDuel(user1StepCount: 12, user2StepCount: 10, user1Name: "Player1",.....
print(activeDuel.standings) // prints "Player1, you lead by 2 points

Related

variable passed by reference before being initialized

I am trying to make a random number generator in swift using 2 user inputs (which are integers) given from the user. I am having a problem generating the number using the function I made with parameters. I get an error stating that both the result1 and result2 variables are being passed by reference before being initialized in the calling to the generate function. EDIT: Gave more info about error
// Here is the full code.
func generate(min: inout Int, max: inout Int) -> Int{
let finalValue=Int.random(in: min...max)
return finalValue
}
print("I am gonna assume this works right.")
print("Pick a number (or 2 but please 1 for now)")
var result1: Int
if let input = readLine() {
if let number = Int(input) {
result1 = number
}
}
var result2: Int
if let input = readLine() {
if let number = Int(input) {
result2 = number
}
}
generate(min: &result1, max: &result2)
You can't guarantee that result1 and result2 have been initialised when you call generate(min: max:) as they are set within if statements. One way around this would be to make them optional, test for that, and bail if still nil.
func generate(min: Int?, max: Int?) -> Int? {
guard let min = min, let max = max else {return nil}
return Int.random(in: min...max)
}
var input1, input2: Int?
if let input = readLine(), let number = Int(input) {
input1 = number
}
if let input = readLine(), let number = Int(input) {
input2 = number
}
generate(min: input1, max: input2)
There are probably better ways of approaching, but this sticks with your original post.

problems with forEach loop

struct Response: Codable {
let status: String
let value: [Value]
}
struct Value: Codable {
let psid: Int
let name: String
let valute: String
let reserve: Double
let with_codes: Int
let img: String
}
var good = [Value]()//first array
struct Response1: Codable {
let status: String
let value: [Value1]
}
struct Value1: Codable {
let id: String
let enabled: Int
let direct: Int
let psid1: Int
let psid2: Int
let in: Int
let in_valute: String
let out: Double
let out_valute: String
let in_min: Double
let in_max: Int
let reserve: Double
}
var good1 = [Value1]()//second array
good.forEach { goodItem in
if good1.contains(where: { good1Item -> Bool in
return good1Item.psid2 == goodItem.psid
}) {
print(goodItem)
}
}
The problem is that when I need to output goodItem.name to a table, only the last value is output, although when I check everything in the console, google I found that the return method returns only the last value, how can I fix it?
This worked for me:
for value in good {
if good1.filter( {$0.psid2 == value.psid}).count > 0 {
print(value.name)
}
}

How to retrieve results from Struct in array

I have an enum and Struct that looks like the following.
enum Position: String {
case lw = "Left Wing"
case rw = "Right Wing"
case c = "Centre"
case d = "Defense"
case g = "Goalie"
}
struct PlayerInformation {
let firstName: String
let lastName: String
let position: Position
let number: Int
}
struct ShiftDetails {
let player: PlayerInformation
var timeOnIce: Int
var dateOnIce: Date
}
I build the playerInformationArray with the following:
var playerInformationArray = [PlayerInformation]()
let sidneyCrosby = PlayerInformation.init(firstName: "Sidney", lastName: "Crosby", position: Position.c, number: 87)
let alexOvechkin = PlayerInformation.init(firstName: "Alex", lastName: "Ovechkin", position: Position.lw, number: 8)
let patrickKane = PlayerInformation.init(firstName: "Patrick", lastName: "Kane", position: Position.rw, number: 88)
playerInformationArray.append(sidneyCrosby)
playerInformationArray.append(alexOvechkin)
playerInformationArray.append(patrickKane)
I store information about a players "shift" in the following array:
var shiftDetails = [ShiftDetails]()
I retrieve the information about the "selected" player from a collection view with the following:
let selectedPlayer = playerInformationArray[indexPath.row]
I then update the shiftDetails array with the following:
shiftDetails.append( ShiftDetails.init(player: selectedPlayer, timeOnIce: timerCounter, dateOnIce: Date()) )
Everything works as excepted, but I'm having a hard time understanding, how to retrieve data from the arrays. For example:
How would I retrieve the count of shiftDetails per player?
How would I retrieve the sum of timeOnIce per player?
Thanks!
If you need to check if certain player is equal to another player you need to make it conform to Equatable protocol implementing the double equal operator ==. You can also make your struct conform to `CustomStringConvertible and provide a custom description to it:
struct Player: Equatable, CustomStringConvertible {
let firstName: String
let lastName: String
let position: Position
let number: Int
static func ==(lhs: Player, rhs: Player) -> Bool {
return lhs.firstName == rhs.firstName && lhs.lastName == rhs.lastName
}
var description: String {
return "Player: " + firstName + " " + lastName
}
}
Also in Swift you should always prefer long names (camelCase) for better readability and try to avoid redundant information when naming your properties and you shouldn't add the type to your object names:
enum Position: String {
case leftWing = "Left Wing"
case rightWing = "Right Wing"
case center = "Center"
case defense = "Defense"
case golie = "Goalie"
}
struct Shift {
let player: Player
var timeOnIce: Int
var dateOnIce: Date
}
var players: [Player] = []
let sidneyCrosby = Player(firstName: "Sidney", lastName: "Crosby", position: .center, number: 87)
let alexOvechkin = Player(firstName: "Alex", lastName: "Ovechkin", position: .leftWing, number: 8)
let patrickKane = Player(firstName: "Patrick", lastName: "Kane", position: .rightWing, number: 88)
players += [sidneyCrosby, alexOvechkin, patrickKane]
var shifts: [Shift] = []
var index = IndexPath(row: 0, section: 0)
var selectedPlayer = players[index.row]
let shift1 = Shift(player: selectedPlayer, timeOnIce: 3, dateOnIce: Date())
shifts.append(shift1)
let shift2 = Shift(player: selectedPlayer, timeOnIce: 5, dateOnIce: Date())
shifts.append(shift2)
To sum timeOnIce property per player and its count, you could extend Array constraining the elements to Shift type:
extension Array where Element == Shift {
func timeOnIceAndCount(for player: Player) -> (timeOnIce: Int, count: Int) {
return reduce((0,0)) {
$1.player == player ? ($0.0 + $1.timeOnIce, $0.1 + 1) : $0
}
}
}
let (timeOnIce, count) = shifts.timeOnIceAndCount(for: selectedPlayer)
print(selectedPlayer)
print("TimeOnIce:",timeOnIce)
print("Count: ", count)
This will print
Player: Sidney Crosby
TimeOnIce: 8
Count: 2
This may not end up being the cleanest way of doing this since all your shiftDetails are held in a single, shared array, but in order to accomplish this with your current setup you could use the built-in filter function to get information about a given player. This could look something like this:
let selectedPlayer = playerInformationArray[indexPath.row]
let filteredDetails = shiftDetails.filter({ $0.player == selectedPlayer })
let shiftCount = filteredDetails.count
let timeOnIce = filteredDetails.reduce(0, { $0 + $1.timeOnIce })
Another option would be to maintain a shiftDetails array for each player, at which point you don't need to do any filtering. Or, another option would be to have the shiftDetails be a dictionary where the key is the player and the value is an array of shiftDetails.
It is also worth noting that my example of the filter function assumes your Player struct conforms to the Equatable protocol - in other words, that you can legally say playerOne == playerTwo. If you don't do this you would have to match on some other unique field such as name or playerId or something like that.

How to convert a String to an Int in Swift?

I'm trying to get the substring of the var num, but I need that substring be an Int How can I do that?
This is my code
func sbs_inicio(num: String, index: Int) -> Int{
let dato: Int = num.index(num.startIndex, offsetBy: index)
return dato
}
var num = "20932121133222"
var value = sbs_inicio(num: num, index: 2)
print(value) //value should be 20
Use the prefix function on the characters array
let startString = "20932121133222"
let prefix = String(startString.characters.prefix(2))
let num = Int(prefix)
Prefix allows you to get the first n elements from the start of an array, so you get these, convert them back to a String and then convert the resulting String to an Int

Swift: The proper way to initialize model class with a lot of properties

How do you initialize your classes/structs with a lot of properties?
This question could probably be asked without Swift context but Swift brings a flavour to it, so I add Swift tag in headline and tags.
Let's say you have a User class with 20 properties. Most of them should not be nil or empty. Let's assume these properties are not interdependent. Let's assume that 33% of it should be constant (let) by the logic of the class. Let's assume that at least 65% of them do not have meaningful default values. How would you design this class and initialize an instance of it?
So far I have few thoughts but none of it seems to be completely satisfactory to me:
put all of the properties linearly in the class and make huge init method:
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date
var lastPlayDate : Date
// then HUUUUGE init
init(id: String,
username: String,
...
lastPlayDate: Date) {
}
}
try to group properties into sub types and deal with smaller inits separately
class User {
struct ID {
let id : String
let username : String
let email : String
}
struct Activity {
var lastLoginDate : Date
var lastPlayDate : Date
}
let id : ID
...
var lastActivity : Activity
// then not so huge init
init(id: ID,
...
lastActivity: Activity) {
}
}
another solution is to break requirements a bit: either declare some of the properties optional and set values after init or declare dummy default values and set normal values after init, which conceptually seems to be the same
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date?
var lastPlayDate : Date?
// then not so huge init
init(id: String,
username: String,
email: String) {
}
}
// In other code
var user = User(id: "1", username: "user", email: "user#example.com"
user.lastLoginDate = Date()
Is there a nice paradigm/pattern how to deal with such situations?
You can try the builder pattern.
Example
class DeathStarBuilder {
var x: Double?
var y: Double?
var z: Double?
typealias BuilderClosure = (DeathStarBuilder) -> ()
init(buildClosure: BuilderClosure) {
buildClosure(self)
}
}
struct DeathStar : CustomStringConvertible {
let x: Double
let y: Double
let z: Double
init?(builder: DeathStarBuilder) {
if let x = builder.x, let y = builder.y, let z = builder.z {
self.x = x
self.y = y
self.z = z
} else {
return nil
}
}
var description:String {
return "Death Star at (x:\(x) y:\(y) z:\(z))"
}
}
let empire = DeathStarBuilder { builder in
builder.x = 0.1
builder.y = 0.2
builder.z = 0.3
}
let deathStar = DeathStar(builder:empire)
Example taken from here: https://github.com/ochococo/Design-Patterns-In-Swift
If you are looking for a bit more Java like solution, you can try something like this.
Alternative Example
final class NutritionFacts {
private let servingSize: Int
private let servings: Int
private let calories: Int
private let fat: Int
private let sodium: Int
private let carbs: Int
init(builder: Builder) {
servingSize = builder.servingSize
servings = builder.servings
calories = builder.calories
fat = builder.fat
sodium = builder.sodium
carbs = builder.carbs
}
class Builder {
let servingSize: Int
let servings: Int
private(set) var calories = 0
private(set) var fat = 0
private(set) var carbs = 0
private(set) var sodium = 0
init(servingSize: Int, servings: Int) {
self.servingSize = servingSize
self.servings = servings
}
func calories(value: Int) -> Builder {
calories = value
return self
}
func fat(value: Int) -> Builder {
fat = value
return self
}
func carbs(value: Int) -> Builder {
carbs = value
return self
}
func sodium(value: Int) -> Builder {
sodium = value
return self
}
func build() -> NutritionFacts {
return NutritionFacts(builder: self)
}
}
}
let facts = NutritionFacts.Builder(servingSize: 10, servings: 1)
.calories(value: 20)
.carbs(value: 2)
.fat(value: 5)
.build()
Example taken from: http://ctarda.com/2017/09/elegant-swift-default-parameters-vs-the-builder-pattern