Use custom init method when programmatically creating a uicollectionview - ios

Due to the limitations of Storyboard I am creating a UICollectionView programmatically. This is working all fine and when I want to add a UICollectionViewCell I do the following:
[collectionView registerClass:[Cell class] forCellWithReuseIdentifier:#"ID"];
What I was wondering is how can I use a custom init method from the class "Cell", because I can't do something like the following:
[collectionView registerClass:[[Cell class]init_custom]forCellWithReuseIdentifier:#"ID"];
Question: How can I use a custom init method from a custom UICollectionViewCell class?

If I understand you correctly, then I would create subclasses of your collection view cell.
First setup your cell with everything you want.
#interface MyCollectionViewCell : UICollectionViewCell
// Your custom cell
#end
#implementation MyCollectionViewCell
// Your custom cell
#end
Then for each collection view create a subclass which only overrides init.
#interface MyCollectionViewCellForCollectionView1 : MyCollectionViewCell
#end
#implementation MyCollectionViewCellForCollectionView1
- (instancetype)init // Only override -init
{
self = [super init];
if (self) {
// Setup for collection view one
}
return self;
}
#end
#interface MyCollectionViewCellForCollectionView2 : MyCollectionViewCell
#end
#implementation MyCollectionViewCellForCollectionView2
- (instancetype)init // Only override -init
{
self = [super init];
if (self) {
// Setup for collection view two
}
return self;
}
#end
Then for each different collection view, you register one of your subclasses.
[collectionView1 registerClass:[MyCollectionViewCellForCollectionView1 class] forCellWithReuseIdentifier:#"ID"];
[collectionView2 registerClass:[MyCollectionViewCellForCollectionView2 class] forCellWithReuseIdentifier:#"ID"];
This will get you the separate custom init methods you wish, but be sure to keep all your functionality in the base class.

Related

Custom UITableViewCell without dequeueReusableCellWithIdentifier

So I have a custom UITableViewCell:
TestTableViewCell.h
#import <UIKit/UIKit.h>
#interface TestTableViewCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *testCellLabel;
#end
TestTabelViewCell.m
#import "TestTableViewCell.h"
#implementation TestTableViewCell
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
_testCellLabel = [[UILabel alloc] init];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
And then I have view controller with a table view that uses the custom table view cell. However this issue is that I don't want to use dequeueReusableCellWithIdentifier within the cellForRowAtIndexPath. I instead want to have an array of cells.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
ViewController.m
#import "ViewController.h"
#import "TestTableViewCell.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSArray *myTableViewCells;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSArray *)myTableViewCells {
TestTableViewCell *cell1 = [[TestTableViewCell alloc] init];
cell1.testCellLabel.text = #"one";
cell1.backgroundColor = [UIColor blueColor];
TestTableViewCell *cell2 = [[TestTableViewCell alloc] init];
cell2.testCellLabel.text = #"two";
cell1.backgroundColor = [UIColor greenColor];
if (!_myTableViewCells) {
_myTableViewCells = #[cell1, cell2];
}
return _myTableViewCells;
}
#pragma mark - UITableView delegate functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.myTableViewCells.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TestTableViewCell *cell = self.myTableViewCells[indexPath.row];
return cell;
}
#end
The problem is that there is no testCellLabel appearing in the table view cell. I know the cells are there, because I set their background colour.
After talking to a few people, apparently I need to do some sort of loading from the XIB or the NIB for the UI to load properly? Even though the label is defined in the cell in the storyboard.
I know this is going against the norm and that Apple really wants you to use dequeueReusableCellWithIdentifier, but I know it won't work in the situation I need it in. I have done the reading on that much so please don't just tell me to use it. This code example is just very basic for example sake and ease of use.
Any help would be greatly appreciated.
TestTableViewCell *cell1 = [[TestTableViewCell alloc] init];
Creates a new TestTableViewCell object and does not instantiate it from the storyboard like you're thinking it does. Therefor all outlets created will be nil and simply not show up. The fact that you can set the background colour is not evidence that your implementation works.
You need to use dequeueReusableCellWithIdentifier. You say that it doesn't work for your problem.. show me how it doesn't work and I will tell you why you're wrong.
Edit
I see in your comments you say your cell needs a custom setter. Well, when you use dequeueReusableCellWithIdentifier you can do all setup work in awakeFromNib (If using a xib file) OR initWithCoder if you are using the storyboard.
You can create cell without dequeueResableCellWithIdentifer.
[[UITableViewCell alloc]initWithStyle:<#UITableCellStyle#> resueIdentifier:<#(nullable *NSString)#>]

how to set initial value of table view cell property in iOS

I have an image property on my table view cell. I want to populate this image to an image.
My cell looks like:
//.h
#interface GAFriendStatusTableViewCell : PFTableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *friendImage;
#end
//.m
#import "GAFriendStatusTableViewCell.h"
#implementation GAFriendStatusTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.friendImage.image = [UIImage imageNamed:#"user.png"];
}
return self;
}
- (void)awakeFromNib
{
// Initialization code
}
#end
This doesn't set the image. How can I set the image for this cell within the cell class?
Since your image view is an IBOutlet, I'm assuming you've got your cell layout defined in a .xib or storyboard. That being the case, your initialization code should go in the awakeFromNib method. This is the method that is called when the cell is created from the nib. That's why the //Initialization code comment is there. initWithStyle:reuseIdentifier: is never called in this scenario, which is why your image is not appearing.
Set it in - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
Otherwise if you have a Nib or Storyboard you're using then set the default in the prototype cell you are using.

How to create a Common Custom TableView Class?

I want to create a custom tableView class, Which can be used in any view Controller. I have to just create tableview object and set an array and frame of tableview . Then this tableview will be add as subview on my view. and also give me a click event.
I just want to avoid writing tableview datasource and delegate method in every viewController class.
Take a viewController or tableviewController class and code all the delegates and data source methods there. now in you view controller where you want to make it as a subview call the tableview class and add it as a subview.
EX:
TableviewContrller *libaray =[TableviewContrller new];
[libaray willMoveToParentViewController:self];
[self.view addSubview:libaray.view];
[self addChildViewController:libaray];
To hide write this code in your tableview controller class
[self.view removeFromSuperView];
As you are using a reusable class you need to send the array information to that class. along with it it will be better to send either class name or setting tag value to tableview
So in your tableview class write this
-(id)initWithInformationArray :(NSMutableArray *)dataArray andTagValueforTableview :(int) tagValue
{
self = [super init];
if (self != nil)
{
NSLog(#"%#", dataArray);
}
return self;
}
Now sub viewing will be like this
TableviewContrller *libaray =[[TableviewContrller alloc]initWithInformationArray:YOURARRAY andTagValueforTableview:TAGVALUE];
[libaray willMoveToParentViewController:self];
[self.view addSubview:libaray.view];
[self addChildViewController:libaray];
Hope this will help.
May be you can use UITableViewController.
UITableViewController is a subclass of UIViewController, when you create a subclass of UITableViewController, the template has the usual methods of tableview datasource and delegate methods.
You'll need to create a custom class and create your own delegate in that class for UITableView. Now whenever you create a UITableView assign that custom class as the class for UITableView.
If you don't know how to create custom delegates then check below links:
http://www.alexefish.com/post/522641eb31fa2a0015000002
http://ios-blog.co.uk/tutorials/quick-tip-create-your-own-objective-c-delegate-protocol/
Hope this will help you :)
You can create BaseTableView class.
#interface BaseTableView : UITableView <UITableViewDelegate, UITableViewDataSource>
{
NSArray* listObject;
}
#property (nonatomic, retain) NSArray *listObject;
-(id) initWithFrame:(CGRect)frame style:(UITableViewStyle)style;
#end
#implementation BaseTable
#synthesize listObject;
-(id) initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
if(self = [super initWithFrame:frame style:style])
{
self.dataSource = self;
self.delegate = self;
}
return self;
}
-(void)setListObject:(NSArray *)listObjectRef
{
[listObject release];
listObject = [listObjectRef retain];
[self reloadData];
}
-(void) dealloc
{
[listObject release];
[super dealloc];
}
#end
Inherit this class for specific use and override following methods according to needs
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
In your ViewController class use following code
SpecificTableView *table = [[SpecificTableView alloc] init];
[table setListObject:((FRFTReportList*)obj)];
Hopefully this will help.

Use my custom initialier to initialize my table cell (inherit UITableViewCell)

I have created my custom table cell class:
#interface CommonCell : UITableViewCell{
...
}
#end
In the implementation file of it, I have created a custom initializer method: initWithCellHeight:reuseIdentifier:showName
which called the [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]) , like below:
#implementation CommonCell
- (id)initWithCellHeight:(float)cellHeight reuseIdentifier:(NSString *)reuseIdentifier showName:(BOOL)showName
{
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier])) {
[self createViews: showName];
}
return self;
}
When I use my cell class in my controller in the following way:
#import "CommonCell.h"
...
cell = [[[CommonCell alloc] initWithCellHeight:150 reuseIdentifier:#"CommonCellId" showName:YES] autorelease];
I got warning message : instance method "initWithCellHeight:reuseIdentifier:showName" not found
Why? Why I can not use my custom initialiser for my table cell?
Why is - (id)initWithCellHeight:(float)cellHeight reuseIdentifier:(NSString *)reuseIdentifier showName:(BOOL)showName not present in the header file? You will need to declare it before using it to remove the warning.

How can I subclass a UITableView?

I want to subclass a UITableView as I want to create a reusable table view component in my application.
The idea is instead of using a delegate for say cellForRowAtIndexPath I want the table view itself to get that call.
I don't think I want a UITableViewController as this UITableView that I want to build has to live in various UIViewControllers (and these UIViewController might have UITableViews of their own).
I subclassed my UITableView as:
#interface ShareUITableView : UITableView
but none of its methods get called.
My ShareUITableView is created via the NIB by setting the custom class to ShareUITableView. I have verified in code that a ShareUITableView is instantiated.
My UITableView does not delegate to its view controller, so that's not the problem.
Any ideas?
If I understood you, you need this class declaration:
#interface ShareUITableView : UITableView <UITableViewDataSource>
And then, in your class constructor, you should assign the instance itself as its own datasource:
- (id)init
{
//...
self.dataSource = self;
//...
}
Of course, the class will have to adopt the protocol.
Good luck!
MyTableView.h
// MyTableView.h
// This overrides the UITableViewDataSource with your own so you can add any methods you would like.
#protocol MyTableViewDataSource <UITableViewDataSource>
#required
// This is where you put methods that are required for your custom table to work (optional)
- (int)myRequiredMethod;
#optional
// This is where you put methods that are optional, like settings (optional)
#end
// This overrides the UITableViewDelegate with your own so you can add any methods you would like.
#protocol MyTableViewDelegate <UITableViewDelegate>
#required
// This is where you put methods that are required for your custom table to work (optional)
#optional
// This is where you put methods that are optional, like settings (optional)
#end
// Make sure you add UITableViewDelegate and UITableViewDataSource implementations.
#interface MyTableView : UITableView <UITableViewDelegate, UITableViewDataSource> {
// Your customer datasource and delegate.
id <MyTableViewDataSource> myDataSource;
id <MyTableViewDelegate> myDelegate;
}
#end
MyTableView.m
// MyTableView.m
#import "MyTableView.h"
#implementation MyTableView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// This is how you can use your custom method.
int i = [myDataSource myRequiredMethod];
}
return self;
}
- (void)awakeFromNib {
// This assigns the delegate and datasource you assigned to File's Owner in your xib to your custom methods
myDataSource = (id<MyTableViewDataSource>)self.dataSource;
myDelegate = (id<MyTableViewDelegate>)self.delegate;
self.delegate = self;
self.dataSource = self;
}
// This is an example of how to override an existing UITableView method.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// This calls the method implemented in your ViewController. See Below.
NSInteger rows = [myDataSource tableView:tableView numberOfRowsInSection:section];
return rows;
}
#end
MyViewController.h
// MyViewController.h
#import "MyTableView.h"
// Use MyTableViewDataSource and MyTableViewDelegate instead of UITableViewDataSource and UITableViewDelegate
#interface MyViewController : UIViewController <MyTableViewDataSource, MyTableViewDelegate> {
#end
MyViewController.m
// MyViewController.m
#import "MyViewController.h"
#interface MyViewController ()
#end
#implementation MyViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
// This method will be overridden by myTableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (int)myRequiredMethod {
return 2;
}
Subclassing is a great way to make reusable custom UI elements.
I think, you should still go with a Controller class. I expect subclassing UITableView to be tedious work — if possible with reasonable amount at all.
There is no problem to have UIViewController/NoViewController implemented the delegate and datasource and yet assign another controller to a specific tableView. note, that the datasource and delegate don't need to be subclasses of UITableViewController.
have a look at this answer: Implement Delegate at Run Time?
My UITableView does not delegate to its view controller, so that's not the problem.
You have to have to use delegate and datasource, that is how TableViews are filled and configured. otherwise you will have to overwrite every method of UITableView — including private ones, a no-go if you want into AppStore. Recreating UITableView without subclassing it would be even easier.

Resources