Offscreen UITableViewCells (for size calculations) not respecting size class?

Update on Dec 2015:

Apple now discourages overriding -traitCollection. Please consider using other workarounds. From the doc:

IMPORTANT

Use the traitCollection property directly. Do not override it. Do not provide a custom implementation.


Original Answer:

The existing answer is great. It explained that the problem is that:

The proposed workaround is to temporarily add the cell to the table view. However, this does NOT work if we are in, say, -viewDidLoad, in which the traitCollection of the table view, or the view of the view controller, or even the view controller itself, is not valid yet.

Here, I propose another workaround, which is to override traitCollection of the cell. To do so:

  1. Create a custom subclass of UITableViewCell for the cell (which you probably did already).

  2. In the custom subclass, add a - (UITraitCollection *)traitCollection method, which overrides the getter of the traitCollection property. Now, you can return any valid UITraitCollection you like. Here’s a sample implementation:

    // Override getter of traitCollection property
    // https://stackoverflow.com/a/28514006/1402846
    - (UITraitCollection *)traitCollection
    {
        // Return original value if valid.
        UITraitCollection* originalTraitCollection = [super traitCollection];
        if(originalTraitCollection && originalTraitCollection.userInterfaceIdiom != UIUserInterfaceIdiomUnspecified)
        {
            return originalTraitCollection;
        }
    
        // Return trait collection from UIScreen.
        return [UIScreen mainScreen].traitCollection;
    }
    

    Alternatively, you can return a suitable UITraitCollection created using any one of its create methods, e.g.:

    + (UITraitCollection *)traitCollectionWithDisplayScale:(CGFloat)scale
    + (UITraitCollection *)traitCollectionWithTraitsFromCollections:(NSArray *)traitCollections
    + (UITraitCollection *)traitCollectionWithUserInterfaceIdiom:(UIUserInterfaceIdiom)idiom
    + (UITraitCollection *)traitCollectionWithHorizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass
    + (UITraitCollection *)traitCollectionWithVerticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass
    

    Or, you can even make it more flexible by doing this:

    // Override getter of traitCollection property
    // https://stackoverflow.com/a/28514006/1402846
    - (UITraitCollection *)traitCollection
    {
        // Return overridingTraitCollection if not nil,
        // or [super traitCollection] otherwise.
        // overridingTraitCollection is a writable property
        return self.overridingTraitCollection ?: [super traitCollection];
    }
    

This workaround is compatible with iOS 7 because the traitCollection property is defined in iOS 8+, and so, in iOS 7, no one will call its getter, and thus our overriding method.

Leave a Comment