CodeRatchet CodeRatchet - 5 months ago 17
iOS Question

Populate List in Swift 2.0 and display results

I've been learning iOS development for the past three weeks, I'm currently following a course on Udemy so far so good.

However I'm following one of the lectures whereby we build an Instagram Clone.

The instructor is using three arrays which are as follows:

var usernames = [""] // Stores all usernames
var userIds = [""] // Stores all Id's of the given usernames
var isFollowing = [false] // Stores where or not you're following that user


To me trying to keep track of what userId goes with what username using two arrays is basically an accident waiting to happen so I decided to set off and find a more feasible approach. I reverted back to my .Net days and decided to create a list so I went and created a class as follows:

class Users{
var Username : NSString = ""
var UserId : NSString = ""
var Following : Bool = false
}


Now inside my
ViewController
I make a call to Parse which returns me a list of users and I'm basically trying to loop through the response, and add them to the list class as shown here:

var t = [Users]() // After googling the web, this seems to be the syntax for a list declaration ?
let u = Users()

for object in users{

if let o = object as? PFUser {

u.Username = o.username!
u.UserId = o.objectId!
u.Following = o.IsFollowing!

self.t.append(u)

}

}

print(self.t)


Now when I print this to the console I see the following:

ParseStarterProject_Swift.Users

As I have one user at present, however when I try to loop through T and display the username in the console it doesn't display anything.

for x in t {

print(x.Username)

}


Please bare with me as I'm new to Swift so my syntax maybe incorrect.

Rob Rob
Answer

Your basic intuition is correct, it's better to have an array of custom objects, not multiple arrays.

Regarding making it more Swifty, consider your Users type. You might want something like:

struct User {   
    let username: String
    let userId: String
    let following: Bool
}

Note,

  • property names should start with lowercase letter;
  • Users should probably be called User, as it represents a single user;
  • we don't generally initialize values to default values like that, but rather specify them in the initializer;
  • we probably use String not NSString;
  • if a property cannot change, you'd use let, not var;
  • properties begin with lower case letters;

Then you can do something like:

var t = [User]()

for object in users {
    if let o = object as? PFUser {
        t.append(User(username: o.username!, userId: o.objectId!, following: o.IsFollowing!)
    }
}

print(t)

Clearly, with all of those ! forced unwrapping operators, you'd want to be confident that those fields were populated for all of those properties.


Using struct is nice because (a) it's a value type; (b) you get the initializer for free; and (c) you can just print them. If you really wanted User to be a reference type (a class), you'd do something like:

class User {
    let username: String
    let userId: String
    let following: Bool

    init(username: String, userId: String, following: Bool) {
        self.username = username
        self.userId = userId
        self.following = following
    }
}

And if you wanted to be able to just print them, you'd define it to conform to CustomStringConvertible:

extension User: CustomStringConvertible {
    var description: String { return "<User; username = \(username); userId = \(userId); following = \(following)>" }
}

With the class, you can feel free to change that description computed property to show it in whatever format you want, but it illustrates the idea.