Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: optional array count

In Objective-C, if I had the following property:

@property (strong, nonatomic) NSArray * myArray;

A method to return a number of objects in myArray would look like:

- (NSInteger) numberOfObjectsInMyArray
{
    return [self.myArray count];
}

This would return either the number of objects in the array, or 0 if myArray == nil;

The best equivalent I can think of for doing this in Swift is:

var myArray: Array<String>?

func numberOfObjectsInMyArray() -> Int
{
   return myArray ? myArray!.count : 0
}

So checking the optional array contains a value, and if so unwrap the array and return that value, otherwise return 0.

Is this the correct way to do this? Or is there something simpler?

like image 333
Ashley Mills Avatar asked Jun 30 '14 13:06

Ashley Mills


3 Answers

Try using the nil coalescing operator.

According to the Apple Documentation:

The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil.

So your function could look like this:

    func numberOfObjectsInMyArray() -> Int {
        return (myArray?.count ?? 0)
    }

I agree with others that this could be a bad idea for a number of reasons (like making it look like there is an array with a count of "0" when there isn't actually an array at all) but hey, even bad ideas need an implementation.

EDIT:

So I'm adding this because two minutes after I posted this answer, I came across a reason for doing exactly what the author wants to do.

I am implementing the NSOutlineViewDataSource protocol in Swift. One of the functions required by the protocol is:

optional func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int

That function requires that you return the number of children of the item parameter. In my code, if the item has any children, they will be stored in an array, var children: [Person]?

I don't initialize that array until I actually add a child to the array.

In other words, at the time that I am providing data to the NSOutlineView, children could be nil or it could be populated, or it could have once been populated but subsequently had all objects removed from it, in which case it won't be nil but it's count will be 0. NSOutlineView doesn't care if children is nil - all it wants to know is how many rows it will need to display the item's children.

So, it makes perfect sense in this situation to return 0 if children is nil. The only reason for calling the function is to determine how many rows NSOutlineView will need. It doesn't care whether the answer is 0 because children is nil or because it is empty.

return (children?.count ?? 0) will do what I need. If children is nil it will return 0. Otherwise it will return count. Perfect!

like image 148
Aaron Rasmussen Avatar answered Nov 04 '22 10:11

Aaron Rasmussen


That looks like the simpler way.

The Objective-C code is shorter only because nil is also a form of 0, being a C-based language.

Since swift is strongly typed you don't have such a shorthand. In this specific case it requires a little more effort, but in general it saves you most of the headaches caused by loose typing.


Concerning the specific case, is there a reason for making the array optional in the first place? You could just have an empty array. Something like this might work for you:

var myArray: Array<String> = []

func numberOfObjectsInMyArray() -> Int {
   return myArray.count
}

(Source for this information)

like image 28
Gabriele Petronella Avatar answered Nov 04 '22 12:11

Gabriele Petronella


How about using optional for return value?

var myArray: Array<String>?

func numberOfObjectsInMyArray() -> Int? {
    return myArray?.count
}

I think that this way is safer.

(Source for this information)

like image 31
Wanbok Choi Avatar answered Nov 04 '22 12:11

Wanbok Choi