Подтвердить что ты не робот

Как я могу наложить NSMutableArray на массив Swift определенного типа?

Я переношу свой проект iOS на Swift. Я занимаюсь этим классом по классам. Когда я вызываю методы Objective C из Swift, многие типы Objective C преобразуются в их Swift-копии.

В моем случае Objective C NSMutableArray преобразуется в Swift Array<AnyObject>. Теперь вот моя проблема. В моем классе Swift я получаю такой массив из объекта Objective C. Теперь, когда я нахожусь в мире Swift, я хотел бы передать этот массив конкретному типу вместо AnyObject, потому что я точно знаю, какие объекты существуют в этом массиве.

Компилятор не позволит мне это сделать! Позвольте мне упростить мою проблему, сказав, что я хочу передать массив, содержащий строки. Это то, что я пробовал:

var strings = myObjcObject.getStrings() as [String]

Я получаю следующую ошибку от компилятора:

'String' не идентичен "AnyObject"

Я должен согласиться с компилятором, поскольку String действительно не идентичен AnyObject. Но я не понимаю, почему это проблема. Я могу сбрасывать AnyObject в String, если хочу, правильно?

Я также пробовал:

var strings = myObjcObject.getStrings() as? [String]

Кажется, это шаг в правильном направлении, но getStrings() возвращает NSMutableArray, поэтому я получаю следующую ошибку:

"NSArray" не является подтипом "NSMutableArray"

Есть ли способ сделать то, что я пытаюсь сделать здесь?

4b9b3361

Ответ 1

Вы можете сделать эту работу с двойным нажатием, сначала на NSArray, затем на [String]:

var strings = myObjcObject.getStrings() as NSArray as [String]

Протестировано на игровой площадке с помощью:

import Foundation

var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
var swiftArray = objCMutableArray as NSArray as [String]

Update:

В более поздних версиях Swift (как минимум 1,2) компилятор будет жаловаться на as [String]. Вместо этого вы должны использовать if let с условным нажатием as?:

import Foundation

var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
if let swiftArray = objCMutableArray as NSArray as? [String] {
    // Use swiftArray here
}

Если вы абсолютно уверены, что ваш NSMutableArray может быть добавлен к [String], тогда вы можете использовать as! вместо этого (но вы, вероятно, не должны использовать это в большинстве случаев):

import Foundation

var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
var swiftArray = objCMutableArray as NSArray as! [String]

Ответ 2

compactMap - ваш друг в Swift 4.1 и выше, а также в Swift 3.3-3.4. Это означает, что у вас нет двойного или принудительного литья.

let mutableArray = NSMutableArray(array: ["a", "b", "c"])
let swiftArray: [String] = mutableArray.compactMap { $0 as? String }

В предыдущих версиях Swift, 2.0-3.2 и 4.0 для этой цели вам понадобится использовать flatMap. Использование такое же, как compactMap:

let swiftArray: [String] = mutableArray.flatMap { $0 as? String }

Ответ 3

С Swift 1.2 будет работать следующее:

let mutableArray = NSMutableArray(array: ["a", "b", "c"])
let swiftArray = NSArray(array: mutableArray) as? [String]

Ответ 4

let mutableArray = NSMutableArray()

mutableArray.add("Abc")
mutableArray.add("def")
mutableArray.add("ghi")

if let array = mutableArray as? [String] {
    print(array)    // ["Abc", "def", "ghi"]
}

Ответ 5

в Xcode 6.3 я использовал следующее:

var mutableArray = NSMutableArray(array:"1", "2", "3")
let swiftArray = mutableArray as AnyObject as! [String]

Ответ 6

для быстрого 3

вы можете рассмотреть следующий код

let array: [String] = nsMutableArrayObject.copy() as! [String]

Ответ 7

В моем случае компилятор хотел, чтобы я написал это так, чтобы подавить все предупреждения и проблемы компиляции, так что не только этот восклицательный знак, даже если поле imagesField уже объявлено с одним, но также скобки и "как!" чтобы убедиться, что никто не жалуется.

(imagesField!.images as! [UIImage]) 🤮

Это заставило меня чувствовать себя довольно неловко... Свифт может быть лучше, его новый язык так... Я сделал расширение:

 public static func cast(_ object: Any) -> Self {
        return object as! Self
    }

Назначено это массиву:

extension Array: CSLang {
}

И теперь я могу написать такое же утверждение, как это с тем же эффектом:

[UIImage].cast(imagesField.images)

Как ни крути, это мой путь, меньше вопросов и восклицательных знаков, лучше. Я сделал также юнит-тест:

func testCast() {
    let array: NSMutableArray? = NSMutableArray()
    array?.add("test string 1")
    array?.add("test string 2")
    let stringArray: [String] = [String].cast(array)
    XCTAssertEqual("test string 2", stringArray[1])
}

Ответ 8

Я создал расширение для NSArray для этого.

extension NSArray {
    func swiftArray<T>() -> [T] {
        let result: [T] = self.compactMap { $0 as? T }
        return result
    }
}

Использование:

class Test {
    var title: String
    init(title: String) {
        self.title = title
    }
}

let mutableArray = NSMutableArray()
mutableArray.add(Test(title: "1"))
mutableArray.add(Test(title: "2"))
mutableArray.add(Test(title: "3"))
mutableArray.add(Test(title: "4"))

let tests: [Test] = mutableArray.swiftArray()