-2

I have a piece of code I've used in an objective c app that I want to incorporate into a new swift project. Problem is I can't work out the syntax!

I'm using FMDB to get some information about sets of cards from a sql database. When I pull the information out of the database I create a card object which has properties described in the database. When I access the database it returns an NSMutableArray of my card objects. I want to explicitly state that my mutable array contains these objects...

I would do this in objective c by writing:

NSMutableArray<Card*>

I'm using it in this context

- (NSMutableArray<Card *> *)getCardsFromDb

So I know my function is returning a mutable array of Card objects. How can I do this in swift?

at the moment the code in my project is minimal

   //Properties
    var cardArray: NSMutableArray<Card>! //How can I tell it that the array is populated with my Card object?

    //View Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        let databaseAccess = DatabaseAccess()

        cardArray = databaseAccess.getCardsFromDatabase()

        print(cardArray)

    }

For the moment I've just called the array a temporary name because I was just testing that the database methods worked. I have tried NSMutableArray[Card] and NSMutableArray(Card) but neither worked.

I would like to do this so that I know when making the database call I am getting an array of card objects, not just some random array.

Thanks

Axemasta
  • 763
  • 1
  • 9
  • 24
  • 2
    Is a Swift array `[Card]` what you are looking for? – You did read the chapter about [collection types](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html) in the "Swift Programming Language" reference, didn't you? – Martin R Jan 05 '18 at 22:36
  • 1
    The best solution is to use a Swift array instead of `NSMutableArray` (or `NSArray`). – rmaddy Jan 05 '18 at 22:36
  • @MartinR I was not familiar with this (thanks) but it doesn't solve my problem as I lose the methods associated with `NSMutableArray` to add the card details to my card object as I iterate through the sql database. – Axemasta Jan 05 '18 at 22:39
  • @Axemasta What methods do you mean? A Swift array has many, many ways to modify and iterate. – rmaddy Jan 05 '18 at 22:47

2 Answers2

3

If you want to declare a variable of type array of Card but not save an array into it, you'd use

var cardArray: [Card]

That's equivalent to the Objective-C

NSMutableArray<Card*> cardArray;

(Or rather, the Objective-C is equivalent to the Swift, since Objective-C adopted typed arrays in order to be compatible with Swift.)

If you want to define a variable of type array of Card and put a blank array into it, you'd use

var cardArray = [Card]()

That's equivalent to

NSMutableArray<Card*> cardArray = [NSMutableArray new];

(Although I forget how you satisfy the type requirement in Objective-C. That Objective-C statement might need minor tweaking...)

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • OP can't declare `var cardArray: [Card]` as a property of his view controller without initializing it unless he declare its type as optional or IUO which wouldn't make any sense in this case. – Leo Dabus Jan 05 '18 at 22:56
  • This worked for me, thanks for the clear explanation! I've converted every instance of `NSMutableArray` with my object array `[Card]`. My database getter function now returns `[Card]` so I can properly use this when I come to populate a tableview with data. Many Thanks! – Axemasta Jan 05 '18 at 23:05
  • Yes, as Leo points out I should have mentioned that if you declare a non-optional property of a class then you need to give it a value at some point before initialization completes. You can either give it a default value when it's declared or give it a default value in the initializer. The effect is pretty much the same. – Duncan C Jan 06 '18 at 12:35
  • The ObjC line at the end is correct (except that you're missing the variable name itself!) -- there's no parameterization on the name of the class in the invocation, just the variable's type. – jscs Jan 06 '18 at 15:16
  • @JoshCaswell thanks for catching the missing variable name. Does the result of the call to `new` need to be cast to type `NSMutableArray` to satisfy the compiler's type checking? – Duncan C Jan 06 '18 at 16:44
  • No, no need to cast. The generics aren't that significant. – jscs Jan 06 '18 at 16:47
1

Since you are writing Swift code, you should declare cardArray as:

var cardArray: [Card] = []

instead of:

var cardArray: NSMutableArray<Card>!

Because getCardsFromDatabase() returns a mutable array (not Swift array), you would need to down cast it first before assign it to cardArray:

override func viewDidLoad() {
    super.viewDidLoad()

    let databaseAccess = DatabaseAccess()

    cardArray = databaseAccess.getCardsFromDatabase() as! [Card]

    print(cardArray)
}
Ahmad F
  • 30,560
  • 17
  • 97
  • 143
  • 2
    Why implicitly unwrapped optional? It doesn't make any sense its usage here – Leo Dabus Jan 05 '18 at 22:49
  • @LeoDabus `cardArray = databaseAccess.getCardsFromDatabase() as! [Card]` is that what you mean? – Ahmad F Jan 05 '18 at 22:51
  • 1
    Do you know the difference between IUO and forced casting? I am talking about `var cardArray: [Card]!` – Leo Dabus Jan 05 '18 at 22:52
  • @LeoDabus honestly, I'm not pretty sure that I got it right, is it related to https://stackoverflow.com/questions/39537177/swift-3-incorrect-string-interpolation-with-implicitly-unwrapped-optionals ? please advice. – Ahmad F Jan 05 '18 at 22:59
  • 1
    Just initialize the array with an empty array instead of declaring it as `[Card]!` – Leo Dabus Jan 05 '18 at 23:01
  • @LeoDabus Edited. I think it wouldn't be different in this case, is it correct? thank you in advance :) – Ahmad F Jan 05 '18 at 23:07
  • You should avoid using implicitly unwrapped optionals as much as possible. – Leo Dabus Jan 05 '18 at 23:08
  • Thanks, I'm pretty behind on my swift and am usually referring to projects I've done in objective c. A better solution was to get my function to return a `[Card]` array so that I dont have to cast anything when using the function. – Axemasta Jan 05 '18 at 23:08
  • @Axemasta if you were able to change the implementation of `getCardsFromDatabase ()` that would be true, you don't even have to deal with `NSMutableArray` at all. – Ahmad F Jan 05 '18 at 23:11
  • @AhmadF Yes thats what I ended up doing. I did this thing on an objective c app, now I try to do everything in swift and was just copying along what I had previously done! I'll keep in mind that I should not be using `NSMutableArray` in swift, if I can help it! – Axemasta Jan 05 '18 at 23:13