3 Replies
      Latest reply on Aug 14, 2019 1:30 AM by eskimo
      WBT Level 1 Level 1 (0 points)

        Hi,

         

        Swift just threw me a warning which is going against what I thought I new.

        If someone can offer some clarification that would be appreciated.

         

        I have an object called deliveryCustomer which contains such fields as

        .id

        .firstname

        .companyName

        etc etc...

         

        I am running a for loop and grabbing an array of customers as follows..

         

        //**LOOP THROUGH THE JSON ARRAY**

                  for anItem in jsonResult as! [Dictionary<String, AnyObject>] {

                                var deliveryCustomer:deliveryCustomers = deliveryCustomers()

         

                                if let idString = (anItem["id"]) as? NSString {

                                    deliveryCustomer.id = idString

                                }

                              

                                if let firstNameString = (anItem["firstName"]) as? NSString {

                                    deliveryCustomer.firstName = firstNameString

                                }

        }

         

        you get the idea...

         

        In my line where I declare var deliveryCustomer, swift is suggesting that I replace this with a let.

         

        My understanding was that once I declare it as a let, I can no longer modify the variable, but in my code, I am modifying it in quite a few locations in the for loop.

         

        Can someone please advise if the warning is correct, and I am able to replace this var as a let??

         

        Thanks,

        Wade.

        • Re: Question about var and let
          Claude31 Level 8 Level 8 (6,355 points)
                    for anItem in jsonResult as! [Dictionary<string, anyobject="">] {
                                  var deliveryCustomer:deliveryCustomers = deliveryCustomers()
          
                                  if let idString = (anItem["id"]) as? NSString {
                                      deliveryCustomer.id = idString
                                  }
                               
                                  if let firstNameString = (anItem["firstName"]) as? NSString {
                                      deliveryCustomer.firstName = firstNameString
                                  }
          }

           

          Line 2, you create the object.

           

          Line 5, you do not change the object reference, you just change one of its properties.

          Hence, the object itself is unchanged.

           

          So, you can replace var with let.

           

          If that can help you, imagine you have a

           

          class Person {
              private var name: String    // Make it private, so that it cannot be changed from outside
              private var firstName: String
              var age: Int
            
              init(name: String, firstName: String, age: Int) {
                  self.name = name
                  self.firstName = firstName
                  self.age = age
              }
          }
          
          
          let someGenius = Person(name: "Einstein", firstName: "Albert", age: 80)
          someGenius.age = 85
          someGenius.name = "Other"  // Error 'name' is inaccessible due to 'private' protection level

           

          someGenius points to a person that will not change. To make it sure, the name and firstName are declared as private.

          But the age can change, of course. That does not change the person, it is still Albert Einstein !

           

          That would be different, if you declared a struct and not a class:

          You get an error with a let declaration

           

          struct Personnage {
              var name: String    // Make it private, so that it cannot be changed from outside
              var firstName: String
              var age: Int
             
              init(name: String, firstName: String, age: Int) {
                  self.name = name
                  self.firstName = firstName
                  self.age = age
              }
          }
          
          let someOne = Personnage(name: "Einstein", firstName: "Albert", age: 80)
          someOne.age = 85    // Cannot assign to property: 'someOne' is a 'let' constant

           

           

          The core reason is that

          - class are reference objects; instance is a reference to the object ; changing the content does not change the instance value

          - struct are value objects: instance is the content ; changing the content does change the instance value.

           

          « Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference. »

          Extrait de: Apple Inc. « The Swift Programming Language (Swift 4). » Apple Books.

            • Re: Question about var and let
              WBT Level 1 Level 1 (0 points)

              Thank you Claude31.

               

              This is exactly what I was after.

               

              I have been thinking about it wrong, but this clarifies it for me.

               

              I was thinking that changing a property variable of the object was changing the class object as well.

               

              Thanks

            • Re: Question about var and let
              eskimo Apple Staff Apple Staff (11,625 points)

              Claude31 has answered the question you asked (yay!) but I was curious if you’ve looked at using Codable for this.  It’s the standard approach for dealing with JSON and it can radically simplify your code.  For example, if you define a struct like this:

              struct Person: Codable {
                  var id: Int
                  var firstName: String
                  var lastName: String
              }

              you can parse JSON [1] in a single line:

              let persons = try! JSONDecoder().decode([Person].self, from: jsonData)

              Share and Enjoy

              Quinn “The Eskimo!”
              Apple Developer Relations, Developer Technical Support, Core OS/Hardware
              let myEmail = "eskimo" + "1" + "@apple.com"

              [1] This line assumes you have input like this:

              let json = """
                  [{
                      "id": 1,
                      "firstName": "Steve",
                      "lastName": "Wozniak"
                  }, {
                      "id": 8,
                      "firstName": "Chris",
                      "lastName": "Espinosa"
                  }]
                  """
              let jsonData = Data(json.utf8)