I want to add a CollectionView inside my ViewController using the same code that I have on a CollectionViewController.
CollectionViewController.m
#interface StoreViewController ()
#property (readwrite, nonatomic, strong) NSArray *latestProducts;
#end
#implementation StoreViewController
- (void)setLatestProducts:(NSArray *)latestProducts {
_latestProducts = latestProducts;
[self.collectionView reloadData];
}
- (Product *)releaseForIndexPath:(NSIndexPath *)indexPath {
return [self.latestProducts objectAtIndex:indexPath.row];
}
- (void)loadData:(id)sender {
[self showLoadingView];
[Product latestProductsWithBlock:^(NSArray *products, NSError *error) {
self.latestProducts = products;
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingView];
});
if (error) {
[[[UIAlertView alloc] initWithTitle:[error localizedDescription] message:[error localizedFailureReason] delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil, nil] show];
}
}];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSLocalizedString(#"Deadstock", nil);
[self.collectionView registerClass:[ProductCell class] forCellWithReuseIdentifier:#"ProductCell"];
[self loadData:nil];
}
#pragma mark - UICollectionViewDelegate
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.latestProducts count];
}
#pragma mark - Collection View Cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"productCell";
ProductCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.product = [self releaseForIndexPath:indexPath];
return cell;
}
#end
ProductCell.m
#implementation ProductCell
- (void)setProduct:(Product *)product {
_product = product;
dispatch_async(dispatch_get_main_queue(), ^{
[self.image setImageWithURL:self.product.thumbnailImageURL];
});
self.image.clipsToBounds = YES;
}
#end
I have an NSObject that parses my cell's content, from my database.
Product.h
#interface Product : NSObject
#property (readonly) NSURL *thumbnailImageURL;
- (instancetype)initWithAttributes:(NSDictionary *)attributes;
+ (void)latestProductsWithBlock:(void (^)(NSArray *products, NSError *error))block;
#end
Following a tutorial I fount online, I created a NSObject file ("ProductDataSource") and on my Storyboard I added an Object to my ViewController and linked it to my CollectionView. I copied the code from my CollectionViewController to ProductDataSource but it's not creating my cells. If I set the numberOfItemsInSection to a number it created the cells but not when I change the code to return [self.latestProducts count]. It might have something to do with "loadData" section I have on my CollectionViewController, since ProductDataSource doesn't have a viewDidLoad method.
- (void)loadData:(id)sender {
[self showLoadingView];
[Product latestProductsWithBlock:^(NSArray *products, NSError *error) {
self.latestProducts = products;
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingView];
});
if (error) {
[[[UIAlertView alloc] initWithTitle:[error localizedDescription] message:[error localizedFailureReason] delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil, nil] show];
}
}];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSLocalizedString(#"Deadstock", nil);
[self.collectionView registerClass:[ProductCell class] forCellWithReuseIdentifier:#"ProductCell"];
[self loadData:nil];
}
Any help? Thanks.
You have to reload the collection view after you get latestProducts. Try to put [self.collectionView reloadData] after [self hideLoadingView];
Put a breakpoint in your cellForItemAtIndexPath method to ensure that method is being hit. If it doesn't get hit, that means you need to set your collection view's datasource.
So if I am understanding correctly, you have an existing UICollectionViewController called CollectionViewController and want to reuse the logic in another UIViewController.
a UICollectionViewController is essentially a UIViewController that has a UICollectionView subview and conforms to the UICollectionViewDataSource and UICollectionViewDelegate protocols.
In order to embed a UICollectionView into your UIViewController, you need to create Delegate and DataSource classes for your CollectionView and assign them in the UIViewController.
There are some good code examples here: UICollectionView with UIViewController As Data Source
GitHub Repo with a small single page app using a CollectionView inside a UIViewController:
https://github.com/pnavk/CollectionViewSample
Related
I followed this tutorial from AppCoda and I noticed that when I create another calendar, choose it (indicated by the checkmark beside it), then hit the Back button, the events in the main UIViewController view are not refreshed. I already added this code in my ViewController.m but nothing new happened:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.tblEvents == nil) {
NSLog(#"Your TableView becomes nil");
return;
}
[self.tblEvents reloadData];
}
Any ideas? Let me know if you need more information.
Edit:
.m
#import "MainViewController.h"
#import "AppDelegate.h"
#interface MainViewController ()
#property (nonatomic, strong) AppDelegate *appDelegate;
#property (nonatomic, strong) NSArray *arrEvents;
- (void)requestAccessToEvents;
- (void)loadEvents;
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.tblEvents.delegate = self;
self.tblEvents.dataSource = self;
[self performSelector:#selector(requestAccessToEvents) withObject:nil afterDelay:0.4];
[self performSelector:#selector(loadEvents) withObject:nil afterDelay:0.5];
[self.tblEvents reloadData];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tblEvents reloadData];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"idSegueEvent"]) {
EventViewController *eventViewController = [segue destinationViewController];
eventViewController.delegate = self;
}
}
#pragma mark - UITableView Delegate and Datasource method implementation
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"%lu", (unsigned long)self.arrEvents.count);
return self.arrEvents.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"idCellEvent"];
// Get each single event.
EKEvent *event = [self.arrEvents objectAtIndex:indexPath.row];
// Set its title to the cell's text label.
cell.textLabel.text = event.title;
// Get the event start date as a string value.
NSString *startDateString = [self.appDelegate.eventManager getStringFromDate:event.startDate];
// Get the event end date as a string value.
NSString *endDateString = [self.appDelegate.eventManager getStringFromDate:event.endDate];
// Add the start and end date strings to the detail text label.
cell.detailTextLabel.text = [NSString stringWithFormat:#"%# - %#", startDateString, endDateString];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60.0;
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
// Keep the identifier of the event that's about to be edited.
self.appDelegate.eventManager.selectedEventIdentifier = [[self.arrEvents objectAtIndex:indexPath.row] eventIdentifier];
// Perform the segue.
[self performSegueWithIdentifier:#"idSegueEvent" sender:self];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the selected event.
[self.appDelegate.eventManager deleteEventWithIdentifier:[[self.arrEvents objectAtIndex:indexPath.row] eventIdentifier]];
// Reload all events and the table view.
[self loadEvents];
}
}
#pragma mark - EEventViewControllerDelegate method implementation
- (void)eventWasSuccessfullySaved
{
// Reload all events.
[self loadEvents];
}
#pragma mark - IBAction method implementation
- (IBAction)showCalendars:(id)sender
{
if (self.appDelegate.eventManager.eventsAccessGranted) {
[self performSegueWithIdentifier:#"idSegueCalendars" sender:self];
}
}
- (IBAction)createEvent:(id)sender
{
if (self.appDelegate.eventManager.eventsAccessGranted) {
[self performSegueWithIdentifier:#"idSegueEvent" sender:self];
}
}
#pragma mark - Private method implementation
- (void)requestAccessToEvents
{
[self.appDelegate.eventManager.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (error == nil) {
// Store the returned granted value.
self.appDelegate.eventManager.eventsAccessGranted = granted;
} else {
// In case of error, just log its description to the debugger.
NSLog(#"%#", [error localizedDescription]);
}
}];
}
- (void)loadEvents
{
if (self.appDelegate.eventManager.eventsAccessGranted) {
self.arrEvents = [self.appDelegate.eventManager getEventsOfSelectedCalendar];
[self.tblEvents reloadData];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
To make UITableView work you need to set the delegate and datasource object like this..
in you ViewController.m file try to add Delegate and DataSource like this.
#interface ViewController ()<UITableViewDelegate, UITableViewDataSource>
#end
now add these two lines in your view did load.
self.tblEvents.delegate = self;
self.tblEvents.dataSource = self;
And check the implimentation of you Data Source methods like this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//This method should return the number of rows you want to create in your tableView
return yourArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourCellIdentifier"];
//Now show what you want to show in your each cell? For Example you just want to show a simple text which is stored in you array.
cell.textLabel.text = [yourArray objectAtIndex:indexPath.row];
//indexPath.row is the numeric index number of each cell. This method will automatically execute exact the same number of time you return in above method.
return cell;
}
Now When your class/View Controller is open you might have zero data in your array and after some manipulation you got some data in your array Either by Call Web-Services/Loading from local Database/ by Passing Reference of array to next ViewController and on coming back to screen you want to refresh your TableView so now calling [tblEvents reloadData] will restart the process from numberOfRowsInSection method to cellForRowAtIndexPath method
I have a problem with connecting a modal segue with a view controller.
In my storyboard, I have a uicollectionview controller connecting a modal segue to a table view embedded in a uiviewcontroller.
The table view contains "filters" to filter the cells in my collection view.
So far I have been able to load the view controller when the user clicks on a button in an action sheet, which opens when the user clicks a bar button item called "more"
PICTURES
My collection view:
The UIActionSheet:
My Filters View Controller
So the problem I am having is when I click the "filters" button in the action sheet, it loads the filters view controller, and when I press the "cancel" button, I am able to close the view controller from my collection view. However, when I press the "Done" button, my collection view disappears.
My Code
MainViewController.m (Collection view)
-(void)openActionSheet {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"What else would like to do?"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"About Backpack", #"Filters", nil];
[actionSheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"Filters"]) {
[self showFilters];
}
}
#pragma mark UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self applyFilters:[NSSet setWithObject:searchBar.text]];
[searchBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (![searchText length]) {
self.dataSource = self.originalDataSource;
self.imageData = self.originalImageData;
[self.collectionView reloadData];
}
}
#pragma mark FiltersViewControllerProtocol
// "Done" button
- (void)filtersSelected:(NSSet *)filters {
[self hideFilters];
[self applyFilters:filters];
}
//"Cancel" button
- (void)filterSelectionCancelled {
[self hideFilters];
}
#pragma mark private
- (void)showFilters {
if (!self.fvc) {
self.fvc = [self.storyboard instantiateViewControllerWithIdentifier:#"filters"];
self.fvc.delegate = self;
_fvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:_fvc animated:YES completion:nil];
}
}
-(void)hideFilters {
[_fvc dismissViewControllerAnimated:YES completion:nil];
}
- (void)applyFilters:(NSSet *)filters {
NSMutableArray *newData = [NSMutableArray array];
NSMutableArray *newItems = [NSMutableArray array];
for (NSString *s in _dataSource) {
for (NSString *filter in filters) {
if ([s rangeOfString:filter options:NSCaseInsensitiveSearch].location != NSNotFound) {
[newData addObject:s];
break;
}
}
}
for(NSInteger i = 0; i < newData.count; i++) {
NSInteger loc = [self locationOfItemGivenName:newData[i]];
backpackIcons *item = _backpackItems[loc];
[newItems addObject:item.image_url];
}
self.dataSource = newData;
self.imageData = newItems;
[self.collectionView reloadData];
}
- (NSInteger)locationOfItemGivenName:(NSString *)name {
NSInteger found = -1;
for(NSInteger i = 0; i < _backpackItems.count; i++) {
backpackIcons *item = _backpackItems[i];
if([item.name isEqualToString:name]) {
found = i;
}
}
return found;
}
FiltersViewController.h (filters table view)
#import <UIKit/UIKit.h>
#protocol FiltersViewControllerProtocol <NSObject>
- (void)filtersSelected:(NSSet *)filters;
- (void)filterSelectionCancelled;
#end
#interface FiltersViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) id<FiltersViewControllerProtocol> delegate;
#end
FiltersViewController.m
#import "FiltersViewController.h"
#interface FiltersViewController ()
#property (nonatomic, strong) NSMutableSet *selectedRowObjects;
//#property (nonatomic, strong) NSArray *filters;
#end
#implementation FiltersViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.selectedRowObjects = [NSMutableSet setWithCapacity:10];
}
- (IBAction)filtersSelected:(id)sender {
[self.delegate filtersSelected:self.selectedRowObjects];
}
- (IBAction)cancelFilterSelection:(id)sender {
[self.delegate filterSelectionCancelled];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"filter" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%u", indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *obj = cell.textLabel.text;
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedRowObjects removeObject:obj];
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedRowObjects addObject:obj];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
Another problem I have having is that the filters table view is not loading my cell labels as well.
I appreciate all help. Thanks to anyone who can!
I have UIcollectionView in my first view of application after Uinavigationviewcontroller just in storyboard just like this :
this is my RootViewController.h
#import <UIKit/UIKit.h>
#interface RootViewController : UICollectionViewController<UICollectionViewDelegate,UICollectionViewDataSource>
#property (nonatomic, strong) NSArray *entries;
#end
and my RootViewController.m :
#import "RootViewController.h"
#import "AppRecord.h"
#import "Cell.h"
#define kCustomRowCount 7
#interface RootViewController () <UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
// the set of IconDownloader objects for each app
#property (nonatomic, strong) NSMutableDictionary *imageDownloadsInProgress;
#end
#implementation RootViewController
#pragma mark
// -------------------------------------------------------------------------------
// viewDidLoad
// -------------------------------------------------------------------------------
- (void)viewDidLoad
{
NSLog(#"inside class");
[super viewDidLoad];
// self.title = #"My Title";
//self.collectionView.delegate = self;
//self.collectionView.dataSource=self;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
NSUInteger count = [self.entries count];
NSLog(#"count: %lu", (unsigned long)count);
if (count == 0)
{
return kCustomRowCount;
}
return count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"inside cell");
AppRecord *appRecord = [self.entries objectAtIndex:indexPath.row];
Cell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MY_CELL" forIndexPath:indexPath];
UIImage *truckImage = [[UIImage alloc] init];
truckImage = [UIImage imageNamed:#"Default.png"];
cell.imageView.image = truckImage;
return cell;
}
#end
now problem is none of my "cellForItemAtIndexPath" or "numberOfItemsInSection" or even "viewDidLoad" getting called and the output on Simulator is black screen.
This is my reload section of AppDelegate class :
__block ParseOperation *weakParser = parser;
parser.completionBlock = ^(void) {
if (weakParser.appRecordList) {
dispatch_async(dispatch_get_main_queue(), ^{
RootViewController *rootViewController = (RootViewController*)[(UINavigationController*)self.window.rootViewController topViewController];
rootViewController.entries = weakParser.appRecordList;
if(weakParser.appRecordList != nil)
NSLog(#"weakParser.appRecordList is Not nill");
[rootViewController.collectionView reloadItemsAtIndexPaths:[rootViewController.collectionView indexPathsForVisibleItems]];
[rootViewController.collectionView reloadData];
});
}
self.queue = nil;
};
[self.queue addOperation:parser];
self.appListData = nil;
}
Did you add the delegate and datasource connection for the collection view? It's the most common mistake, usually. They're commented out in code, I assume you did that via Storyboard
Do you have identifier on the storyboard cell?You can try to add
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"MY_CELL"];
in viewDidLoad
Since your RootViewController inherit UICollectionViewController you don't need to add UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout at all
I use the tapGesture method to pouch the image from UICollectionView to detailViewController
viewController.h as follows:
#import <Parse/Parse.h>
#interface CardsViewController : UIViewController <UICollectionViewDelegateFlowLayout> {
NSMutableArray *allImages;
NSArray *cardFileArray;
}
#property (weak, nonatomic) IBOutlet UICollectionView *imageCollection
and viewController.m as the follow
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [cardFileArray count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"MyCell";
Cards *cell = (Cards *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
PFObject *imageObject = [cardFileArray objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:KEY_IMAGE4];
cell.spinController.hidden = NO;
[cell.spinController startAnimating];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
cell.imageView.image = [UIImage imageWithData:data];
[cell.spinController stopAnimating];
cell.spinController.hidden = YES;
}
}];
return cell;
}
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture{
CGPoint touchPoint = [gesture locationInView:imageCollection];
NSUInteger touchPage = floorf(touchPoint.x / imageCollection.frame.size.width);
NSIndexPath *indexPath = [imageCollection indexPathForItemAtPoint:touchPoint];
if (indexPath == nil) {
touchPage = touchPage % ([allImages count]);
}
//Push the image to another view
detailViewController*ptvc = [self.storyboard instantiateViewControllerWithIdentifier:#"imageDetail"];
[self.navigationController pushViewController:ptvc animated:YES];
ptvc.imageString = [cardFileArray objectAtIndex:touchedPage];
}
the detailViewController.h as follow
#property (strong, nonatomic) IBOutlet UIImageView *Preview;
#property (strong, nonatomic) UIImage *imagePreview;
so for the DetailViewController i put in viewDidload this line
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//self.imageView.image = [UIImage imageNamed:self.imageViewDetail];
self.Preview.image = self.imagePreview;
}
but the app make crash and mark the line on the viewDidload
; so any advice i need to puch the image on uicollectionView to detailView
to solve this first you need to identify the image in didselect from parse and declare the segue as well as following
[self performSegueWithIdentifier:#"showDetails" sender:imageCollection];
PFObject *object = [cardFileArray objectAtIndex:indexPath.row];
PFFile *file = [object objectForKey:KEY_IMAGE4];
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
Cards *recipe = [[Cards alloc] init];
recipe.imageView.image = [UIImage imageWithData:data];
}
}];
then you perform the Segue method and link to the detail view as normal and not the following
link you segue to the "you cell" and the imageview in the cell
Finally, import your cell to the detail view and declare it in your header file (this will be linked to your segue)
i hope this will help you
Two things
Remove the tap gesture recognizer and use
-(void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
I see you are using storyboards.. just connect the two view controllers by a push segue. Set an UIImage as property of the detailViewController
-(void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
//store indexPath.row to a variable accessible outside this function
selectedRow = indexPath.row;
[self performSegueWithIdentifier:#"detail" sender:nil];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DetailViewController *detail = [segue destinationViewController];
[detail setImageForDetail:[UIImage imageWithData:[allImages objectAtIndex:selectedRow]]];
//imageArray is the array used to populate the imageCollectionView and i assume they are stored as NSDATA
}
in DetailViewController.h, add
#property (strong,nonatomic) UIImage *imageForDetail;
in DetailViewController.m viewDidLoad add,
self.Preview.image = self.imageForDetail;
I create a UITableViewController using storyboard, and want to reload the tableview every time it detect a device(for bonjour protocol).
However, the reload data method only calls numberofRows, but not call CellForRowatIndexPath. So I have nothing changed. The mutablearray I checked is always going correctly. NewObjects are added. But the tableview doesn't change with the array. So I am wondering if I set sth wrong here.
From the NSLog I added, I found, I could load the tableview at the beginning with
the initialized array
self.serviceArray = [[NSMutableArray alloc]initWithObjects:#"test", nil];
But in the method
- (void)addService:(NSNetService *)....
Everytime I reload, the new object can be added to the mutableArray, but the tableview doesn't change with the array. (It called the numberOfRows, and I check the array size returned is not 0, but then it doesn't call the cellOfRowAtIndex)
Here is my code
.h file
#import <UIKit/UIKit.h>
#import "Server.h"
#interface BrowserViewController : UITableViewController <ServerDelegate>
{
Server *_server;
NSMutableArray *_serviceArray;
}
#property (retain,nonatomic) NSMutableArray *serviceArray;
#property (nonatomic,retain) Server *server;
- (void)addService:(NSNetService *)service moreComing:(BOOL)more;
#end
.m file
#import "BrowserViewController.h"
#implementation BrowserViewController
#synthesize serviceArray = _serviceArray;
#synthesize server = _server;
- (void) dealloc
{
[self.serviceArray release];
[self.tableView release];
[super dealloc];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
self.title = #"Service Browser";
_serviceArray = nil;
self.serviceArray = nil;
[self.tableView setDelegate: self];
[self.tableView setDataSource:self];
//actually I set this in the storyboard already
[self.tableView reloadData];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
_serviceArray = nil;
NSLog(#"viewwilldisappear");
}
- (NSMutableArray *)serviceArray {
if(nil == _serviceArray) {
self.serviceArray = [[NSMutableArray alloc]initWithObjects:#"test", nil];
}
else
{
NSLog(#"update array");
}
return _serviceArray;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)addService:(NSNetService *)service moreComing:(BOOL)more{
[self.serviceArray addObject:service];
if (!more) {
[self.tableView reloadData];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return #"Connection Choices";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.serviceArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *Cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (Cell == nil) {
Cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
}
NSString *text = [self.serviceArray objectAtIndex:indexPath.row];
Cell.textLabel.text = text;
return Cell;
}
#end
I checked some solution, it's either delegate setting problem, or the array is null. or cell initialized without space. Is there any way to check what's the delegate of some method ?
I also tried to create a tableview property in the .h file, linked IBOutlet, then synthesize it in the .m. But still doesn't work. Could anyone help me?
Since a lot of tutorials are based on window-based application, could someone maybe provide me some tutorial using storyboard and using reloadData ? I could check if the Outlets are wrong.
Thanks in advance.
UPDATE1
AddService method is called in the appDelegate
appDelegate.h
#import <UIKit/UIKit.h>
#import "Server.h"
#class BrowserViewController;
#interface iphoneNetworkAppDelegate : NSObject <UIApplicationDelegate,UITableViewDataSource, UITableViewDelegate, ServerDelegate>
{
Server *_server;
UIWindow *window;
IBOutlet BrowserViewController *BrowserVC;
}
#property (strong, nonatomic) UIWindow *window;
#end
appDelegate.m
#import "iphoneNetworkAppDelegate.h"
#import "BrowserViewController.h"
#implementation iphoneNetworkAppDelegate
#synthesize window;
- (void)dealloc
{
[window release];
[_server release];
_server = nil;
[BrowserVC release];
BrowserVC = nil;
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString *type = #"TestingProtocol";
_server = [[Server alloc] initWithProtocol:type];
_server.delegate = self;
NSError *error = nil;
if(![_server start:&error]) {
NSLog(#"error = %#", error);
}
BrowserVC = [BrowserViewController alloc];
if (BrowserVC == nil) {
NSLog(#"need to init");
}
BrowserVC.server = _server;
return YES;
}
#pragma mark Server Delegate Methods
- (void)serverRemoteConnectionComplete:(Server *)server {
NSLog(#"Server Started");
BrowserVC.server = server;
}
- (void)serverStopped:(Server *)server {
NSLog(#"Server stopped");
}
- (void)server:(Server *)server didNotStart:(NSDictionary *)errorDict {
NSLog(#"Server did not start %#", errorDict);
}
- (void)server:(Server *)server didAcceptData:(NSData *)data {
NSLog(#"Server did accept data %#", data);
}
- (void)server:(Server *)server lostConnection:(NSDictionary *)errorDict {
NSLog(#"Server lost connection %#", errorDict);
}
- (void)serviceAdded:(NSNetService *)service moreComing:(BOOL)more {
NSLog(#"service added in delegate");
[BrowserVC addService:service moreComing:more];
}
#pragma mark -
- (void)applicationWillTerminate:(UIApplication *)application {
[_server stop];
[_server stopBrowser];
}
If the appDelegate setting is like this, reloadData cannot be called ?
Please check this terms may help you:
self.tableView is object bind in TableView in XIB.
Included <UITableViewDelegate,UITableViewDataSource> delegates in .h file?
Properly set getter setter your object "self.tableView"
Delegate set?
a)[self.tableView setDelegate: self];
b)[self.tableView setDataSource:self];
i think No need for the following lines in view will appear
_serviceArray = nil;
self.serviceArray = nil;
And also makes sure that the function addService got called: