Search code examples
swiftnsarrayflatmapswift-extensions

Convert NSArray to Array in extension in Swift


I am trying to make a Swift extension for NSArray that uses some Swift methods but am having trouble with the firsts step of creating a properly formatted Swift Array from the NSArray.

The incoming NSArray looks like

[@"Hello",@"Me",@"That",@"Me",@"Hello",@"Me",@"as",@"the"]

Here are different versions of the extension:

This version creates a valid array but because the array is an NSArray, not an array, fails on the line counts[item] with error

cannot subscript a value of type '[String : Int]' with an index of type 'Any'

public extension NSArray {
public var sortedArray: NSArray {
let array : NSArray = self
for item in array {
    counts[item] = (counts[item] ?? 0) + 1
    }
    print("counts",counts)

The next one works but is not taking the array as an input

public extension NSArray {
public var sortedArray: NSArray {
var array = ["Hello","Me","That","Me","Hello","Me","as","the"] 
for item in array {
    counts[item] = (counts[item] ?? 0) + 1
    }
    print("counts",counts)

The following two methods compile but array2 and array3 end up being empty

public extension NSArray {
public var sortedArray: NSArray {
var array2: [String] = self.flatMap { $0 as? String } //This compiles but array is empty
var array3: [String] = self.compactMap({ $0 as? String }) //This compiles but 
for item in array2 {
    counts[item] = (counts[item] ?? 0) + 1
    }
    print("counts",counts)//prints 0 as the array is empty

Note: when I insert a breakpoint at beginning of extension, self is a valid NSArray with lots of elements.

Thanks for any suggestions.


Solution

  • It's worth noting that NSArray bridging has become very good in recent versions of swift. For example, all of the below works

    let array: NSArray = NSArray(array: [3, 2, 1])
    print(array)
    print(type(of: array))
    let newArray = array.compactMap { $0 as? Int }.compactMap(UInt8.init)
    print(newArray)
    
    print(array.sorted(by: { (left, right) -> Bool in
        guard let left = left as? Int, let right = right as? Int else {
            return false
        }
        return left < right
    }))
    

    I think NSArray gets compactMap and friends from conformace to the Sequence protocol. So the standard library is doing all it can to help you out here. Like @Rob mentioned, it's probably better to work with the bridging and not try to stay in NSArray-land