UICollectionView Datasource Methods - ios

UICollectionView has some built-in datasource methods, such as the "cellforItemAtIndexPath" method and the "numberofitemsinsection" method. If I understand correctly, these methods are called after viewDidLoad() completes. However, for my purposes, I want to be able to exactly control the point in time in which these methods are called. How can I do that?
The reason is that I am loading loading some images and I want to finish the task of loading before these methods are called.

It sounds like you don't want to show the collection until the images are downloaded, is that right? Does returning 0 for the number of items until the images finish downloading work? I don't have my Mac with me, or I'd test this before posting.

Disconnect the collectionView datasource and delegate connected to the controller from storyboard. Then set them in the code once you needed.
First connect the collectionView outlet to the interface section.
#interface YourViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate>
#property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
So once your images are loaded, call this method:-
self.collectionView.delegate= self;
self.collectionView.dataSource= self;
[self.collectionView reloadData];

Related

UICollectionView subclass to be reused in multiple viewControllers

I want to create a self-contained UICollectionView subclass (acting as its own data source and delegate) so that I could load it in different viewControllers. Here's what I have so far:
CustomCollectionView.h
#interface CustomCollectionView : UICollectionView <UICollectionViewDataSource, UICollectionViewDelegate>
#property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
#end
CustomCollectionView.m
#import "SSCalendarView.h"
#implementation SSCalendarView
#synthesize collectionView;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
[self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Identifier"];
[self addSubview:collectionView];
}
return self;
}
// Below are UICollectionViewDataSource and UICollectionViewDelegate methods
#end
CustomCollectionView.xib
Contains only one view - UICollectionView. It's class is set to CustomCollectionView
File's Owner's class is also set to CustomCollectionView
File's Owner is UICollectionView's delegate and data source
I understand that I have quite a few things wrong here. But perhaps we could use this as a starting point.
My questions are:
How to implement this sub-class correctly? I want to load the view fully from xib
To begin with, and aside from potential MVC violation (this sub-class would do it all), can a UICollectionView be its own data source and delegate?
If above is possible, how do I correctly create an instance of this subclass to use in my view controllers?
There already exists an object which you can use for this purpose - UICollectionViewController. This can be subclassed and added to any view controller (as a child view controller) and already contains a collection view which it is the datasource and delegate for.
The problems with your current approach are:
As you point out, you're putting too much responsibility on one object by having a view be its own datasource and delegate
File's owner for a xib can't be an object from within the xib. When you load the xib, the object you send to the owner argument is the file's owner. I've no idea what you actually end up with using the code you currently have.
I'm not sure why you insist on using a xib anyway - what does this give you, except the headache of an extra file and the complexity of nib loading? Just create a collection view controller, you can specify the layout and register cells in the init and viewDidLoad methods.
First of all making view to act like view controller is violation of MVC, ask you've said so - so you shouldn't probably do it.
Theoretically it's possible to force view to act as delegate & data source but I wouldn't recommend it.
If you still want to do it - just assign delegate & data source to self:
self.dataSource = self;
self.delegate = self;
and adopt UICollectionViewDelegate and UICollectionViewDataSource protocols in .h file

UITableView (IBOutlet) becomes null after initial data loaded

This has been driving me mad - I have a Class ParentViewController (no xib) with #property picTable, and then ChildViewController (subclass of ParentViewController) with xib and the picTable part of File's Owner linked up.
I noticed the problem as I need to add in more data from a URLRequest - I have the data in an NSArray, but calling reloadData does nothing - and breakpoints are showing that self.picTable is then null - but it is definitely linked (checked via breakpoints) earlier in the view's lifecycle.
I've tried using NSNotificationCenter, a dispatch queue and [self performSelectorOnMainThread... all to no avail - my refreshTableView is always called but the breakpoints show the table view as null.
Tried -
#property (nonatomic, strong) IBOutlet UITableView *picTable;
And -
#property (nonatomic, retain) IBOutlet UITableView *picTable;
Links to the two classes:
Parent:
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicPresentingViewController.h
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicPresentingViewController.m
Subclass:
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicViewController.h
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicViewController.m
Even though you call [super initWithNibNamed...] from the subclass, I'm doubtful that the nib is hooking up the tableview to the superclass. Even if it is important to your design to have the tableView property defined in the superclass, try moving the tableView property down to the subclass and see if it works then.

Why is self.tableView nil when I (think I) set it up correctly?

I have added my custom UICollectionViewController as an object (A) to the interface builder, and given it the proper custom class.
this EOCollectionViewController is also an IBOutlet in my main Viewcontroller
I have added the UICollectionView to the main view of the application.
I have made all the links possible. UICollectionView has the object (A) as a delegate and a datasource.
The object (A) has the UICollectionView linked to the view property. (not the self.collectionView property, as this is not there)
It all works well. Collection view get's filled. The CollectionViewController resides in the property of my main view controller.
Only the self.collectionView is nil...when I try to reach it from within the UICollectionViewController.
My first guess is that "extra" UIControllers used in IB do not get initalized in the same way. I also tested, and viewDidLoad and init never get called for these extra objects.
Attached the header of EONoteController (and the IBOutlet added as a work-around)
#interface EONoteController : UICollectionViewController<UIGestureRecognizerDelegate>{
__weak IBOutlet UICollectionView *cvNotes;
}
#property (nonatomic) EDAMNotebook* notebook;
#property id <EODragHandler> draghandler;
#end
My first guess was to "fix" it, in the viewDidLoad, as follows
self.collectionView = self.view, but viewDidLoad never get's called.
What am i Missing?

Loading multiple tableviews in a UIView (UIView Controller)

I've been searching all throughout the internet for assistance, however there has been little to no solutions to my issue at hand. My project that im trying to get a gasp on is somewhat unique (UI is not exactly following the typical norms).
Current Development Enviroment:
xcode 4
storyboards instead of nibs
Below is a diagram of what i am trying to accomplish -- all within a UIView Controller:
UIView is the light grey background
UITableView 1 - this is a static (or it can be dynamic, thats another challenge) UITableview which will hold different numeric
values for calculation
UITableView 2 - this is a UITableview which will hold calculated results every time it is run.
UIImageView 1 - this is a calculated image example (I have that figured out)
Im sure experienced developers are fully aware of my issue, and or what im about to ask. I understand that a static UITableView is required to be in a tableview controller, but I need to display both the UItableView's at the same time which means it has to be within a UIView.
I can make the interface look the way I need it to through the IB however when trying to compile and build I receive the error that requires the UITableView's to be within a UITableViewController and not a UIView Controller. I have seen many examples using a master-detail layout, but the only stipulation is that this UITableview NEEDS to be displayed 100% of the time when in this view.
So basically, I am asking for direction... but a code example never hurt either! Thank you 100x's over!
-Jonathan
UITableViewController is just a specialized UIViewController specially designed to display full screen UITableViews. It is (quite) equivalent to use an UITableViewController subclass or an UIViewController <UITableViewDataSource, UITableViewDelegate> subclass to manage a tableview.
So even if UITableViewController has some more spiecialized behaviors (automatically creates the UITableView if it does not exists, scrolls it automatically to display the keyboard, sets itself as the delegate and dataSource of the unique UITableView it manages, etc), you can use a standard UIViewController to manage a UITableView and be its dataSource to fill it.
That's even a way to manage a tableview that is not taking the full screen (as UITableViewController expects its view property to directly be the UITableView it manages, not a subview of its main view or whatever, and thus expects the UITableView to take the whole screen, contrary to using an UIViewController that has an UITableView as a custom-sized subclass of its view)
So in your case, you can have an UIViewController that has two IBOutlets, one for each tableView, and that unique UIViewController can be the dataSource (and delegate) of both the UITableViews. That's not a problem. Just be careful then in your datasource methods to distinguish if you are returning data for the first or the second UITableView to feed the correct tables each time.
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, retain) IBOutlet UITableView* masterTableView;
#property (nonatomic, retain) IBOutlet UITableView* detailsTableView;
#end
#implementation MyViewController
#synthesize masterTableView = _masterTableView;
#synthesize detailsTableView = _detailsTableView;
// Proper memory mgmt not shown here:
// - don't forget to set self.masterTableView and self.detailsTableView to nil in viewDidUnload
// - and to release _masterTableView and _detailsTableView in your dealloc method
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell* cell;
if (tableView == self.masterTableView)
{
static NSString* kMasterCellIdentifier = #"MasterCell";
cell = [tableView dequeueReusableCellWithIdentifier:kMasterCellIdentifier];
if (!cell)
{
cell = [[[UITableViewCell alloc] initWithReuseIdentiier:kMasterCellidentifier] autorelease];
// do some configuration common to all your master cells
}
// configure the rest of your cell for each property that is different from one cell to another
}
else if (tableView == self.detailsTableView)
{
// Do exactly the same principle, but for the cells of your "details" TableView
}
return cell;
}

ios - how to create an IBAction for a UITableView?

I am not certain whether I need an IBAction for a UITableView, but what I am trying to do is have some sort of control that I can hide it during page load, and then populate its cells with data that I get from a remote server, and then display that UITableView.
How can I do that? When I currenly try to press control and drag the UITableView to the ViewController, it gives me optons of: dataSource or delegate. I chose dataSource, but then was not sure what to do next.
I tried to do something like this in the .h
#interface MyBusinessesController : UIViewController
- (IBAction)businessList:(id)sender;
#property (weak, nonatomic) IBOutlet UITableView *businessListProperty;
#end
and this in the .m
#import "MyBusinessesController.h"
#interface MyBusinessesController ()
#end
#implementation MyBusinessesController
#synthesize businessListProperty;
...
but it seems I am way off. What is the right way to do what I am trying to do?
Thank you!
If I understand your question correctly you want a UITableView to be hidden when the view loads and download some info from a server in the background then when all data is finished downloading display the table view? Why do you need an IBAction? In viewDidLoad set the "businessListProperty" table to hidden, self.businessListProperty.hidden=TRUE;
then use an NSURLConnection to download the info from the server and in connectionDidFinishLoading set the table view to whatever data you downloaded and then set its hidden value to false.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
//set tableview to whatever you downloaded here
self.businessListProperty.hidden=FALSE;
}
-Shrdder2794

Resources