Oscar Apeland
Oscar Apeland

Reputation: 6662

What's the difference between these two lines?

I'm using a GitHub repo named MNCalendar, and I wanted to call some cells. Now, here's how I did it.

MNCalendarViewDayCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
MNCalendarViewDayCell *cell = (MNCalendarViewDayCell*)[self.collectionView cellForItemAtIndexPath:indexPath];

The first line gave me an issue about it being a MNCalendarViewDayCell pointer to UICollectionViewCell, but the other one was fine. What's going on under the hood here, why is the bottom one correct?

Not critical bug, just an issue, just wondering and trying to learn something from it :)

Upvotes: 3

Views: 155

Answers (6)

Abizern
Abizern

Reputation: 150785

cellForItemAtIndexPath: returns a UICollectionViewCell instance. But you are assigning it to a MKCalendarViewCell variable.

If MKCalendarViewCell is a subclass of UICollectionViewCell, then there isn't really a problem under the Liskov Substitution Principle. And Objective-C is a dynamic language so this is supported.

The error you are seeing comes from the compiler, telling you that you are assigning an object of one type to a variable of the other type. And by casting it you are saying that although the return type is of one class, you know better and that it is actually an instance of another class. This now becomes your problem to verify that this is actually the case.

Upvotes: 1

pNre
pNre

Reputation: 5376

In both statements your are downcasting a UICollectionViewCell to MNCalendarViewDayCell. Since MNCalendarViewDayCell is a subclass of UICollectionViewCell it may implement methods that are not implemented in UICollectionViewCell, this is why you get the warning. Using (MNCalendarViewDayCell *) forces the cast and drops the warning.

Upvotes: 0

lxt
lxt

Reputation: 31304

cellForItemAtIndexPath returns a pointer to a UICollectionViewCell object, but you're assigning the result to a MNCalendarViewDayCell.

The warning is the compiler telling you "hey - this variable you've declared is a MNCalendarViewDayCell, but it looks like you're assigning an object of a different type to it'.

In this case, this is intentional - you've created a custom sub-class of UICollectionViewCell. This mis-matched type won't cause any problems. So to prevent the warning we do what's called casting: we tell the compiler even though the method says it will return a pointer to one class we expect it to be another:

MNCalendarViewDayCell *cell = (MNCalendarViewDayCell*)[self.collectionView cellForItemAtIndexPath:indexPath];

Upvotes: 2

NightFury
NightFury

Reputation: 13546

cellForItemAtIndexPath returns you UICollectionViewCell, not your custom MNCalendarViewDayCell. So when you assign result to MNCalendarViewDayCell *cell, it raises error (According to OOP, parent doesn't know about it's child, but child knows about his parent). So you simply typecast it into your child cell.

Upvotes: 0

Kirsteins
Kirsteins

Reputation: 27345

[self.collectionView cellForItemAtIndexPath:indexPath] returns UICollectionViewCell. Not all UICollectionViewCell objects are MNCalendarViewDayCell, that's why you get the warning. By explicit cast (MNCalendarViewDayCell *) you tell compiler that it is MNCalendarViewDayCell.

Upvotes: 1

Nicholas Smith
Nicholas Smith

Reputation: 11764

So the first one grabs a pointer to a UICollectionViewCell, which is what the base class of MNCalendarViewDayCell is. However whilst it's a super class you can't just assign it to a subclass, so what the (MNCalendarViewDayCell *) does is to say that you're going to cast the pointer from it's base class UICollectionViewCell into the subclass instead. That's why the second one works, as you're converting it to the right type needed for assignment.

Upvotes: 0

Related Questions