Class written with initWithFrame -- I want to instantiate from Storyboard

856 Views Asked by At

I want to use UIExpandableTableView - https://github.com/OliverLetterer/UIExpandableTableView#readme.

I've run into a problem because it's only initializer is initWithFrame:

#pragma mark - Initialization

- (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
    if ((self = [super initWithFrame:frame style:style])) {
        self.maximumRowCountToStillUseAnimationWhileExpanding = NSIntegerMax;
        self.expandableSectionsDictionary = [NSMutableDictionary dictionary];
        self.showingSectionsDictionary = [NSMutableDictionary dictionary];
        self.downloadingSectionsDictionary = [NSMutableDictionary dictionary];
        self.animatingSectionsDictionary = [NSMutableDictionary dictionary];
    }
    return self;
}

I've been trying to initialize the tableView from Storyboard and realized the errors I'm seeing are because this initWithFrame is never being called and the NSMutableDictionaries aren't being initialized. How to solve this?

If not easily solvable I can just instantiate programmatically and go with initWithFrame, but besides wanting to use Storyboard, I'm also curious what a solution would be.


EDIT Here is how these properties and their ivars are declared in UIExpandableTableView. This is in the .h file:

@interface UIExpandableTableView : UITableView <UITableViewDelegate, UITableViewDataSource, NSCoding> {

@private id __UIExpandableTableView_weak _myDelegate; id __UIExpandableTableView_weak _myDataSource;

NSMutableDictionary *_expandableSectionsDictionary;     // will store BOOLs for each section that is expandable
NSMutableDictionary *_showingSectionsDictionary;        // will store BOOLs for the sections state (nil: not expanded, 1: expanded)
NSMutableDictionary *_downloadingSectionsDictionary;    // will store BOOLs for the sections state (nil: not downloading, YES: downloading)
NSMutableDictionary *_animatingSectionsDictionary;

NSInteger _maximumRowCountToStillUseAnimationWhileExpanding;

BOOL _onlyDisplayHeaderAndFooterViewIfTableViewIsNotEmpty;
UIView *_storedTableHeaderView;
UIView *_storedTableFooterView;

}

Here's the top of the .m file of UIExpandableTableView. T

@interface UIExpandableTableView ()

@property (nonatomic, retain) NSMutableDictionary *expandableSectionsDictionary;
@property (nonatomic, retain) NSMutableDictionary *showingSectionsDictionary;
@property (nonatomic, retain) NSMutableDictionary *downloadingSectionsDictionary;
@property (nonatomic, retain) NSMutableDictionary *animatingSectionsDictionary;

@property (nonatomic, retain) UIView *storedTableHeaderView;
@property (nonatomic, retain) UIView *storedTableFooterView;

- (void)downloadDataInSection:(NSInteger)section;

- (void)_resetExpansionStates;

@end
4

There are 4 best solutions below

0
On

I'd do the following:

- (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
    if ((self = [super initWithFrame:frame style:style])) {
        [self setup];
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    [self setup];
}

- (void)setup {
    self.maximumRowCountToStillUseAnimationWhileExpanding = NSIntegerMax;
    self.expandableSectionsDictionary = [NSMutableDictionary dictionary];
    self.showingSectionsDictionary = [NSMutableDictionary dictionary];
    self.downloadingSectionsDictionary = [NSMutableDictionary dictionary];
    self.animatingSectionsDictionary = [NSMutableDictionary dictionary];
}
2
On

All you have to do is remove initWithFrame: and override initWithCoder: instead. This method will be called when an interface builder element reaches init to allow you to setup your dictionaries. And don't worry about eliminating the style and frame arguments because both of those cases will be handled from within interface builder.

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        NSLog(@"%s",__PRETTY_FUNCTION__); // Proof of call
        self.maximumRowCountToStillUseAnimationWhileExpanding = NSIntegerMax;
        self.expandableSectionsDictionary = [NSMutableDictionary dictionary];
        self.showingSectionsDictionary = [NSMutableDictionary dictionary];
        self.downloadingSectionsDictionary = [NSMutableDictionary dictionary];
        self.animatingSectionsDictionary = [NSMutableDictionary dictionary];
    }
    return self;
}
2
On

you could subclass from UIExpandableTableView, and do

- (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
    if (self = [super initWithFrame:frame style:style]) {
        [self configure];
    }
    return self;
}


-(id)initWithCoder:(NSCoder *)aCoder {
    if(self = [super initWithCoder:aCoder]){ 
        [self configure];
    }
   return self;
}


-(void) configure {
    self.maximumRowCountToStillUseAnimationWhileExpanding = NSIntegerMax;
    self.expandableSectionsDictionary = [NSMutableDictionary dictionary];
    self.showingSectionsDictionary = [NSMutableDictionary dictionary];
    self.downloadingSectionsDictionary = [NSMutableDictionary dictionary];
    self.animatingSectionsDictionary = [NSMutableDictionary dictionary];
}

Nibs and Storybord instantiation is don via initWithCoder:

Subcalssing allows you to use third-party code unpatched in this case.

0
On

I think this is simplest solution...you don't have to worry about how the view controller is being initialized.

-(void)viewDidLoad
{
    [super viewDidLoad];
    self.maximumRowCountToStillUseAnimationWhileExpanding = NSIntegerMax;
    self.expandableSectionsDictionary = [NSMutableDictionary dictionary];
    self.showingSectionsDictionary = [NSMutableDictionary dictionary];
    self.downloadingSectionsDictionary = [NSMutableDictionary dictionary];
    self.animatingSectionsDictionary = [NSMutableDictionary dictionary];
}