OdieO
OdieO

Reputation: 7004

Comparing array of force unwrapped optionals

I'm writing a test:

    func test_arrayFromShufflingArray() {

        var videos = [MockObjects.mockVMVideo_1(), MockObjects.mockVMVideo_2(), MockObjects.mockVMVideo_3()]
        let tuple = ShuffleHelper.arrayFromShufflingArray(videos, currentIndex:1)

        var shuffledVideos = tuple.0
        let shuffleIndexMap = tuple.1


        // -- test order is different
        XCTAssert(videos != shuffledVideos, "test_arrayFromShufflingArray fail")
    }

But on the last line I get the last line:

Binary operator '!=' cannot be applied to two '[VMVideo!]' operands

Upvotes: 3

Views: 439

Answers (3)

OdieO
OdieO

Reputation: 7004

Martin R's answer was the better answer, but for this specific purpose I just converted to NSArray's and was able to use the == operator in Swift:

func test_arrayFromShufflingArray() {

    let videos = [MockObjects.mockVMVideo_1(), MockObjects.mockVMVideo_2(), MockObjects.mockVMVideo_3()]
    let videosNSArray: NSArray =  videos.map { $0 }
    let tuple = ShuffleHelper.arrayFromShufflingArray(videos, currentIndex:1)

    let shuffledVideos = tuple.0
    let shuffledVideosNSArray: NSArray =  shuffledVideos.map { $0 }


    // -- test order is different
    XCTAssert(videosNSArray != shuffledVideosNSArray, "test_arrayFromShufflingArray fail")


    // -- test elements are the same
    let set = NSSet(array: videos)
    let shuffledSet = NSSet(array: shuffledVideos)
    XCTAssert(set == shuffledSet, "test_arrayFromShufflingArray fail")
}

Upvotes: 0

Martin R
Martin R

Reputation: 539795

Arrays can be compared with == if the element type is Equatable:

/// Returns true if these arrays contain the same elements.
public func ==<Element : Equatable>(lhs: [Element], rhs: [Element]) -> Bool

But neither ImplicitlyUnwrappedOptional<Wrapped> nor Optional<Wrapped> conform to Equatable, even if the underlying type Wrapped does.

Possible options are (assuming that VMVideo conforms to Equatable):

  • Change your code so that videos and shuffledVideos are [VMVideo] arrays instead of [VMVideo!].

  • Compare the arrays elementwise:

    XCTAssert(videos.count == shuffledVideos.count
        && !zip(videos, shuffledVideos).contains {$0 != $1 })
    
  • Define a == operator for arrays of implicitly unwrapped equatable elements:

    func ==<Element : Equatable> (lhs: [Element!], rhs: [Element!]) -> Bool {
        return lhs.count == rhs.count && !zip(lhs, rhs).contains {$0 != $1 }
    }
    

Upvotes: 2

BaseZen
BaseZen

Reputation: 8718

Swift can't tell how to compare two arrays to see if their contents are identical unless it knows how to compare individual elements. So you need to implement the == function on your class and adopt Equatable:

extension VMVideo: Equatable {
    // nothing goes here, == function has to be at global scope
}

func ==(lhs: VMVideo, rhs: VMVideo) -> Bool {
    // Up to you to determine what equality means for your object, e.g.:
    return lhs.essentialProperty1 == rhs.essentialProperty1 &&
        lhs.essentialProperty2 == rhs.essentialProperty2
}

EDIT To clarify how it interacts with NSObject and to troubleshoot your environment, please confirm the following:

class UnderstandsEqual: NSObject {}
let ok1: [UnderstandsEqual] = [UnderstandsEqual(), UnderstandsEqual()]
let ok2: [UnderstandsEqual] = [UnderstandsEqual(), UnderstandsEqual()]
ok1 == ok2 // no problem, evaluates to true

class DoesntUnderstand {}
let bad1: [DoesntUnderstand] = [DoesntUnderstand(), DoesntUnderstand()]
let bad2: [DoesntUnderstand] = [DoesntUnderstand(), DoesntUnderstand()]
bad1 == bad2 // produces a compile-time error

Upvotes: 0

Related Questions