I've been trying to configure a custom UICollectionViewCell that is supposed to present a UIView consisting of a few subviews generated with a custom method.
The problem is that when I try to pass the needed data from -cellForItemAtIndexPath to the cell's properties (NSStrings) the app crashes and the data doesn't seem to be passed at all, because NSLog returns (null) for all of the properties.
I thought that the problem was with the properties not being initialized, but when I initialized them in -initWithFrame, they didn't return any values. I tried to use the -initWithCoder and -awakeFromNib and it didn't work.
I also tried to utilize a custom method that would set the properties for me. While it seems to be working, I can't seem to find a way to add the generated view to the cell's view, as using [self.contentView addSubview:...] seems to be adding every generated view to every cell in the Collection View.
If you guys could help me out, I would be much grateful - I've spent my entire day on this, and I just can't get it to work. Perhaps I should do it differently?
My custom collection view cell's .h file:
#import "SHDesignChicago.h"
#interface SHDesignChicagoCollectionViewCell : UICollectionViewCell
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSString *date;
#property (strong, nonatomic) NSString *going;
#property (strong, nonatomic) PFFile *background;
#property (strong, nonatomic) UIView *generatedDesign;
- (void)setCellWithEventName:(NSString *)name eventDate:(NSString *)date eventGoing:(NSString *)going eventBackground:(PFFile *)background;
#end
And my custom collection view cell's .m file:
#import "SHDesignChicagoCollectionViewCell.h"
#implementation SHDesignChicagoCollectionViewCell
- (void)setCellWithEventName:(NSString *)name eventDate:(NSString *)date eventGoing:(NSString *)going eventBackground:(PFFile *)background {
UIImage *backgroundImage = [[UIImage alloc] initWithData:[background getData]];
NSLog(#"Event details:\nName: %#\nDate: %#\nGoing: %#\nBackground: %#", name, date, going, background);
self.generatedDesign = [SHDesignChicago designWithName:name date:date going:going background:backgroundImage frame:self.frame];
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
//self.autoresizesSubviews = YES;
__block UIImage *backgroundImage;
[self.background getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) backgroundImage = [[UIImage alloc] initWithData:data];
}];
NSLog(#"Event details:\nName: %#\nDate: %#\nGoing: %#\nBackground: %#", self.name, self.date, self.going, self.background);
if (self.name != nil) {
UIView *generatedDesign = [SHDesignChicago designWithName:self.name date:self.date going:self.going background:backgroundImage frame:self.frame];
[self addSubview:generatedDesign];
}
}
return self;
}
#end
Also the cellForItemAtIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PFObject *event = [self.events objectAtIndex:indexPath.row];
NSString *name = event[#"eventName"];
NSDate *date = event[#"eventDate"];
PFFile *background = event[#"coverPhoto"];
if ([event[#"designId"] isEqual: #(1)]) {
// SHDesignChicago
SHDesignChicagoCollectionViewCell *chicagoCell = (SHDesignChicagoCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"chicago" forIndexPath:indexPath];
/*
chicagoCell.name = #"TEST";
chicagoCell.date = #"TODAY, 5 PM";
chicagoCell.going = #"NATALIA KAWECKA AND 35 OTHERS ARE GOING";
chicagoCell.background = background;
*/
[chicagoCell setCellWithEventName:name eventDate:#"TODAY, 5 PM" eventGoing:#"NATALIA M AND 35 OTHERS ARE GOING" eventBackground:background];
return chicagoCell;
}
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
return cell;
}
Related
I added a simple collection view and i add items fetched from my backend , when I add all the objects to a nsmutablearray it takes less memory but when I add the fetched objects to a NSObject while scrolling the collection view it takes more memory .
here is a sample code
myObjectModel.h
#import <Foundation/Foundation.h>
#interface myObjectModel: NSObject
#property (nonatomic, strong) NSString *objectTitle;
#property (nonatomic, strong) NSString *objectDesc;
#property (nonatomic, strong) NSString *objectImgURL;
- (id)initWithObjectTitle:(NSString *)dTitle
objectImgURL:(NSString *)dObjectImgURL
objectDesc:(NSString *)dObjectDesc;
#end
myObjectModel.m
#import "myObjectModel.h"
#implementation myObjectModel
- (id)initWithObjectTitle:(NSString *)dTitle
objectImgURL:(NSString *)dObjectImgURL
objectDesc:(NSString *)dObjectDesc {
self = [super init];
if (self) {
self.objectTitle = dTitle;
self.objectImgURL = dObjectImgURL;
self.objectDesc = dObjectDesc;
}
return self;
}
#end;
then I imported this header to my UIViewController which has a collectionview while fetching all the objects i add this method to add those objects and then save them into a nsmutablearray
BackendlessDataQuery *query = [BackendlessDataQuery query];
query.queryOptions.pageSize = #(100); //set page size
[[backendless.persistenceService of:[Channels class]] find:query response:^(BackendlessCollection *backendlessObjects) {
NSArray *currentPage = [backendlessObjects getCurrentPage];
NSMutableArray *arrData = [[NSMutableArray alloc]init];
for (Objects *objects in currentPage) {
#autoreleasepool {
myObjectModel *dataItem = [[myObjectModel alloc]initWithObjectTitle:backendlessObjects.title
objectImgURL:backendlessObjects.image
objectDesc:backendlessObjects.Desc;
[arrData addObject:dataItem];
}
//Test is a nsarray added in the header file
self.test = arrData;
[self.collectionView reloadData];
} error:^(Fault *fault) {
}];
here is what I add to my collection data source
#pragma mark - UICollectionViewDatasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView; {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [test count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
myCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"data" forIndexPath:indexPath];
myObjectModel *dataItem = (myObjectModel*)[test objectAtIndex:indexPath.row];
// cell.objectTitle.text = dataItem.objectTitle;
[cell.channelImg sd_setImageWithURL:[NSURL URLWithString:dataItem.objectImgURL] placeholderImage:[UIImage imageNamed:#"NoImage.png"]];
return cell;
}
when I run this code all my objects will appear in the collectionview but while scrolling the memory keeps increasing.
There is no reason to increase memory by using test Array the reason is by using this
[cell.channelImg sd_setImageWithURL:[NSURL URLWithString:dataItem.objectImgURL] placeholderImage:[UIImage imageNamed:#"NoImage.png"]];
this will Asynchronously download image from URL.if you comment above line then it may not increase memory.
I have a project that displays a feed of statuses similar to other social networks. Each feed item has several button that do different things. 1 of the buttons opens a new viewcontroller that displays the comments that have been posted on a particular status. When this button is clicked and the view controller is opened i would like it to be a push segue so that their is a back button and the user can navigate back to the feed.
When this button is clicked and the new vc is launched some unique data about the particular status/cell being clicked needs to be sent to the "comments vc ". Where would the code for doing this go?
CUSTOM CELL .H
#import <UIKit/UIKit.h>
#interface FeedItemCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *DefaultImg;
#property (weak, nonatomic) IBOutlet UILabel *NameLabel;
#property (weak, nonatomic) IBOutlet UILabel *StatusLabel;
#property (weak, nonatomic) IBOutlet UILabel *timeLabel;
#property (nonatomic, copy) NSString *msg_id;
#property (nonatomic, copy) NSString *status;
#property (nonatomic, weak) IBOutlet UIButton* commentButton;
#property (nonatomic, weak) IBOutlet UIButton* bumpButton;
#property (strong, nonatomic) id delegate;
-(IBAction)viewComments:(id)sender;
-(IBAction)bump:(id)sender;
#end
#protocol CustomCellProtocol <NSObject>
- (void)EBCellPressed:(NSString *)cellName;
CUSTOM CELL .M
#import "FeedItemCell.h"
#import "CommentsViewController.h"
#import "NSDate+TimeAgo.h"
#interface FeedItemCell() <WYPopoverControllerDelegate>
{
}
- (IBAction)open:(id)sender;
- (void)close:(id)sender;
#end
#implementation FeedItemCell
#synthesize commentButton;
- (instancetype)initWithDelegate:(id)delegate {
self = [super init];
if (self) {
self.delegate = delegate;
// Initialization code
}
return self;
}
-(IBAction)bump:(id)sender{
[self.delegate EBCellPressed:#"NAME"];
}
- (IBAction)open:(id)sender
{
}
#end
publicFeed . M
#import "PublicFeedViewController.h"
#import "FeedItemCell.h"
#import "AFNetworking.h"
#import "UIImageView+WebCache.h"
#import "InboxDetailViewController.h"
#import "SWRevealViewController.h"
#import "CommentsViewController.h"
#import "NSDate+TimeAgo.h"
#interface PublicFeedViewController (){
NSArray *NameLabel;
NSArray *StatusLabel;
NSMutableArray *feedArray;
}
#end
#implementation PublicFeedViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//The below code prompts the user for push notifications. If allowed, code in AppDelegate takes over and stores the token.
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
// Do any additional setup after loading the view.
self.FeedTable.dataSource=self;
self.FeedTable.delegate=self;
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"foo": #"bar"};
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
[manager POST:#"www" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
//NSLog(#"JSON: %#", responseObject);
self->feedArray = [responseObject objectForKey:#"feed"];
[self.FeedTable reloadData];
[UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return feedArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier=#"Cell";
FeedItemCell *Cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!Cell){
Cell = [[FeedItemCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSLog(#"FEED ARRAY: %#", self->feedArray);
NSDictionary *tempDictionary= [self->feedArray objectAtIndex:indexPath.row];
// Display recipe in the table cell
NSString *thumb_img = [tempDictionary objectForKey:#"thumb_img"];
NSString *thumb_path=#"http://buhzhyve.com/CI_REST_LOGIN/UPLOADS/thumbs/";
NSString *thumb_url = [thumb_path stringByAppendingString:thumb_img];
Cell.NameLabel.text=[tempDictionary objectForKey:#"first_name"];
Cell.StatusLabel.text=[tempDictionary objectForKey:#"message"];
Cell.msg_id=[tempDictionary objectForKey:#"msg_id"];
//Cell.status=[tempDictionary objectForKey:#"message"];
Cell.StatusLabel.lineBreakMode=0;
Cell.StatusLabel.numberOfLines=0;
NSString *commentCount = [tempDictionary objectForKey:#"comment_count"];
NSString *commentButtonText =[NSString stringWithFormat:#"Comments ( %# )",commentCount];
[Cell.commentButton setTitle:commentButtonText forState: UIControlStateNormal];
NSString *bumpCount = [tempDictionary objectForKey:#"bump_count"];
NSString *bumpButtonText =[NSString stringWithFormat:#"Bumps ( %# )",bumpCount];
[Cell.bumpButton setTitle:bumpButtonText forState: UIControlStateNormal];
//[Cell.StatusLabel sizeToFit];
NSString *created_string=[tempDictionary objectForKey:#"created"];
double created_double = created_string.doubleValue;
NSDate *date = [[NSDate alloc] initWithTimeIntervalSince1970:created_double];
NSString *ago = [date timeAgo];
Cell.timeLabel.text=ago;
//Cell.DefaultImg.image = [UIImage imageNamed:#"buhz_mini_logo.png"];
[Cell.DefaultImg setImageWithURL:[NSURL URLWithString:thumb_url]
placeholderImage:[UIImage imageNamed:#"buhz_mini_logo.png"]];
return Cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Ideally you should do lazy loading so that instead of creating a new textView each time, you just reuse the same one.
UITextView *temp = [[UITextView alloc] initWithFrame:CGRectMake(82, 26, self.FeedTable.frame.size.width, 18)]; //This initial size doesn't matter
NSDictionary *tempDictionary= [self->feedArray objectAtIndex:indexPath.row];
NSString *status = [tempDictionary objectForKey:#"message"];
temp.font =[UIFont fontWithName:#"System" size:12];
temp.text = status;
CGFloat textViewWidth = 218;
CGRect tempFrame = CGRectMake(82,26,textViewWidth,18); //The height of this frame doesn't matter.
CGSize tvsize = [temp sizeThatFits:CGSizeMake(tempFrame.size.width, tempFrame.size.height)]; //This calculates the necessary size so that all the text fits in the necessary width.
//Add the height of the other UI elements inside your cell
return tvsize.height + 70;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"commentSegue"]) {
}
}
#end
publicfeed .h
#import <UIKit/UIKit.h>
#interface PublicFeedViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *FeedTable;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton;
- (IBAction)addItem;
#end
So assuming that you're creating this button in code, this is how you could handle this.
This first line tells the button that when it's pressed, it needs to call this specific selector/method sent as the action.
[button addTarget:self action:#selector(showNextViewController) forControlEvents:UIControlEventTouchUpInside];
Then you would create this method in the same class.
- (void) showNextViewController
{
NewViewController *newViewController = [[NewViewController alloc] init]; //Edit this line of course to fit for your situation. I'm not sure if you're loading from an XIB or from a Storyboard, or neither.
newViewController.someVariable = someVariable;
newViewController.someOtherVariable = someOtherVariable;
[[[[[UIApplication sharedApplication] delegate] window] rootViewController].navigationController pushViewController:view animated:YES];
}
This will send the necessary data to the new view controller, and it will also display the new view on the screen with a back button.
Hope this works!
1. Ok so lets pretend this is your custom cell class.
in your .h file of the custom cell you need to add a protocol.
#import <UIKit/UIKit.h>
#interface CustomCell : UIView
#property (strong, nonatomic) id delegate; //this is used for sending messages out of the custom cell
//init
- (id)initWithFrame:(CGRect)frame andCatName:(NSString *)name andDelegate:(id)delegate;
#end
#protocol CustomCellProtocol <NSObject>
-(void)customCellSelected:(NSString *)cellName;
#end
what we actually did is something like creating a custom event that the class can throw out and everyone who subscribes to that can run a method when customCellSelected is thrown.
2. now when you create each custom cell with the init method you need to provide a delegate which kind of points to which class should the custom cell transfer the call to customCellSelected so in the init method you set that delegate.
- (id)initWithFrame:(CGRect)frame andDelegate:(id)delegate {
self = [super initWithFrame:frame];
if (self) {
self.delegate = delegate; //setting which class should be called when calling protocol methods.
// Your initialization code
}
return self;
}
3. now in your .m file of the custom cell, when the user presses your button and you enter your method , let it be buttonPressed
- (IBAction) buttonPressed:(id)sender {
[self.delegate customCellSelected:#"THE CELL'S NAME"]; // calling the protocol method.
}
now the call to the delegate method should be transferred to the vc because when you create the custom cell you use initWithFrame:(CGRect)frame andDelegate:(id)delegate and you transfer self as the delegate , so when [self.delegate customCellSelected:#"THE CELL'S NAME"]; is called it is actually called on the vc.
4. this is how you create the custom cell in the vc:
customCell *tempView = [[customCell alloc] initWithFrame:CGRectMake(X, Y, Width, Height) andDelegate:self]; // here you set the vc as the delegate
5.and now all you have to do is add the method customCellSelected to your vc code so it can called when the customCell is calling it.
- (void)customCellSelected:(NSString *)cellName {
self.selectedCell = cellName;
[self performSegueWithIdentifier:#"SelectedCell" sender:self];
}
6.then add this in the vc:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"SelectedCell"]) {
LevelSelectViewController *levelSelectViewController = (LevelSelectViewController *)segue.destinationViewController;
levelSelectViewController.cellName = self.selectedCell;
}
}
7.only thing you have to remember is to create a segue from your first vc to the second like this:
To preface, I have some experience with iOS development, but this is my first app that I am going to publish to the AppStore, and also my first experience utilizing UICollectionView.
Here is a summary of what I am doing in my app:
I have a paged UICollectionView which contains several fullscreen UICollectionViewCells. Within each of these cells is another UICollectionView ('subCollectionView'), containing UICollectionViewCells ('subCollectionViewCells') which currently have their label set to "Test Text". When scrolling to the second collectionViewCell, the subCollectionViewCells of the first collectionViewCell are visible behind the second collectionViewCell's subCollectionView. I have linked the images to what is happening here.
The CollectionViewCell that includes the subCollectionView:
[VLCategoryCollectionViewCell.h]
#import <UIKit/UIKit.h>
#interface VLCategoryCollectionViewCell : UICollectionViewCell
#property (nonatomic, strong) NSString *imageName;
#property (strong, nonatomic) IBOutlet UIView *moduleSubview;
- (void)updateCell;
#end
[VLCategoryCollectionViewCell.m]
#import "VLCategoryCollectionViewCell.h"
#import "VLModuleViewController.h"
#interface VLCategoryCollectionViewCell()
#property (strong, nonatomic) IBOutlet UIImageView *imageView;
#property (strong, nonatomic) IBOutlet UILabel *categoryName;
#property (strong, nonatomic) VLModuleViewController *moduleViewController;
#end
#implementation VLCategoryCollectionViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray *arrayOfViews = [[NSBundle mainBundle]
loadNibNamed:#"VLCategoryCollectionViewCell" owner:self options:nil];
if ([arrayOfViews count] < 1) {
return nil;
}
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
return nil;
}
self = [arrayOfViews objectAtIndex:0];
}
return self;
}
-(void)updateCell {
_moduleViewController = [[VLModuleViewController alloc] initWithNibName:#"VLModuleViewController" bundle:nil];
_moduleViewController.view.frame = self.moduleSubview.bounds;
[self.moduleSubview addSubview:_moduleViewController.view];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Assets"];
NSString *filename = [NSString stringWithFormat:#"%#/%#", sourcePath, self.imageName];
UIImage *image = [UIImage imageWithContentsOfFile:filename];
NSString *fileTitle = [[filename lastPathComponent] stringByDeletingPathExtension];
[self.categoryName setFont:[UIFont fontWithName:#"OpenSans-ExtraBold" size:72.0]];
[self.categoryName setText:fileTitle];
[self.imageView setImage:image];
[self.imageView setContentMode:UIViewContentModeScaleAspectFit];
}
#end
[VLModuleViewController.h]
#import <UIKit/UIKit.h>
#interface VLModuleViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
#end
[VLModuleViewController.m]
#import "VLModuleViewController.h"
#import "VLModuleCollectionViewCell.h"
#interface VLModuleViewController ()
#property (nonatomic, strong) IBOutlet UICollectionView *moduleView;
#property (nonatomic, strong) NSArray *moduleArray;
#property (nonatomic) int currentIndex;
#property (nonatomic) NSString *cellIdentifier;
#end
#implementation VLModuleViewController
- (void)loadView {
[super loadView];
NSArray *moduleArray = [[NSBundle mainBundle] pathsForResourcesOfType:#"png" inDirectory:#"Module_Tests"];
NSMutableArray *moduleImageArray = [[NSMutableArray alloc] initWithCapacity:[moduleArray count]];
for (NSString *path in moduleArray) {
[moduleImageArray addObject:[UIImage imageWithContentsOfFile:path]];
}
self.moduleArray = [NSArray arrayWithArray:moduleArray];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupCollectionView];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.moduleView setPagingEnabled:YES];
[self.moduleView setCollectionViewLayout:flowLayout];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark -
#pragma mark UICollectionView methods
- (void)setupCollectionView {
[self.moduleView registerClass:[VLModuleCollectionViewCell class] forCellWithReuseIdentifier:#"VLModuleCollectionViewCell"];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.moduleView setCollectionViewLayout:flowLayout];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.moduleArray count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
VLModuleCollectionViewCell *cell = (VLModuleCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"VLModuleCollectionViewCell" forIndexPath:indexPath];
cell.titleLabel.text = #"Module Title Goes Here";
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(235, 147);
}
#end
I had a similar issue with labels overwriting themselves in collectionView, try calling your updateCell method in awakeFromNib, this did the trick for me.
Hi in my app i have to load images to UITableViewCell .which are coming from the server.so the problem is when ever i scroll the tableview images are loading every time and its loading lazy so i tried to stop reusing cells but its not working ,How to stop reusing the cells in UITableView.
my code is
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"Cell";
RestaurantCustomCell *cell =(RestaurantCustomCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSArray *topLevelObjects ;
topLevelObjects= [[NSArray alloc]init];
if(cell==nil)
{
topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"RestaurantCustomCell" owner:self options:nil];
for(id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (RestaurantCustomCell *) currentObject;
break;
}
}
}
NSDictionary *dict=[restauarantsArr objectAtIndex:indexPath.row];
NSString *imgStr=[dict valueForKey:#"Img"];
[self processImageDataWithURLString:imgStr andBlock:^(NSData *imageData) {
if (self.view.window)
{
UIImage *img = [UIImage imageWithData:imageData];
if(img!=nil)
{
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
[img drawInRect:CGRectMake(0,0,100,100)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
cell.restaurantImg.image=newImage;
UIGraphicsEndImageContext();
}
}
}];
cell.nameLbl.text=[dict valueForKey:#"Restaurants"];
cell.typeLbl.text=[dict valueForKey:#"Rest_Cuisine"];
cell.timingsLbl.text=[dict valueForKey:#"Rest_Timings"];
cell.categoryLbl.text=[dict valueForKey:#"Rest_Category"];
cell.addressLbl.text=[dict valueForKey:#"Address"];
return cell;
}
You can not doing this in default table view cell. If you want to create this kind of things then you need to create custom tableview cell anbd do it what you want.
You have to make a custom cell like that:
RestaurantCustomCell.h
#import <UIKit/UIKit.h>
#interface RestaurantCustomCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *nameLbl;
#property (weak, nonatomic) IBOutlet UILabel *typeLbl;
#property (weak, nonatomic) IBOutlet UILabel *timingsLbl;
#property (weak, nonatomic) IBOutlet UILabel *categoryLbl;
#property (weak, nonatomic) IBOutlet UILabel *addressLbl;
#property (weak, nonatomic) IBOutlet UIImageView *restauranImg;
#end
RestaurantCustomCell.m
#import "RestaurantCustomCell.h"
#implementation RestaurantCustomCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)prepareForReuse{
self.nameLbl.text = #"";
self.typeLbl.text = #"";
self.timingsLbl.text = #"";
self.categoryLbl.text = #"";
self.addressLbl.text = #"";
}
#end
after in IB you add a new UITableViewCell at your UITableView and the class of it with you new custom cell set the Identify ID like "RestaurantCustomCell" add your labels and imageView to your custom cell and connect the Outlet, then you modify you tableView:cellForRowAtIndexPath: like that:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"RestaurantCustomCell";
RestaurantCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *dict=[restauarantsArr objectAtIndex:indexPath.row];
NSString *imgStr=[dict valueForKey:#"Img"];
[self processImageDataWithURLString:imgStr andBlock:^(NSData *imageData) {
if (self.view.window)
{
UIImage *img = [UIImage imageWithData:imageData];
if(img!=nil)
{
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
[img drawInRect:CGRectMake(0,0,100,100)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
cell.restaurantImg.image=newImage;
UIGraphicsEndImageContext();
}
}
}];
cell.nameLbl.text=[dict valueForKey:#"Restaurants"];
cell.typeLbl.text=[dict valueForKey:#"Rest_Cuisine"];
cell.timingsLbl.text=[dict valueForKey:#"Rest_Timings"];
cell.categoryLbl.text=[dict valueForKey:#"Rest_Category"];
cell.addressLbl.text=[dict valueForKey:#"Address"];
return cell;
I have a UITableViewCell nib file in which there is a UIImageView and a UILabel. I have outlets for both of these to my controller as well as an outlet for the cell itself. I am setting the label and image programmatically, but the image does not show up.
So I went to test it, and even if I set the image itself in the nib file, it does not show up. If I set the background color, it shows up fine. Any ideas? I'm stuck.
It seems to be unrelated to code, in my mind, since it doesn't even work via nib file. But here it is anyway in case it helps somehow.
MyViewController.h
#interface MyViewController : UITableViewController
#property (strong, nonatomic) MyModel *myModel;
#property (strong, nonatomic) NSArray *tableViewCells;
#property (strong, nonatomic) IBOutlet UITableViewCell *tableViewCell;
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#property (weak, nonatomic) IBOutlet UIImageView *myImage;
#end
MyViewController.m
#interface MyViewController ()
- (void)bindMyModel:(MyModel*)model toView:(UITableViewCell*)view;
- (UITableViewCell*)copyUITableViewCell:(UITableViewCell*)cell;
#end
#implementation MenuViewController
#synthesize myModel = _myModel;
#synthesize tableViewCells = _tableViewCells;
#synthesize tableViewCell = _tableViewCell;
#synthesize myLabel = _myLabel;
#synthesize myImage = _myImage;
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *cells = [[NSMutableArray alloc] init];
[MyModel loadAndOnSuccess:^(id data, id context) {
self.myModel = data;
for (MyModel *item in self.myModel.items) {
[[NSBundle mainBundle] loadNibNamed:#"TableCellNib" owner:self options:nil];
[self bindMyModel:item toView:self.tableViewCell];
[cells addObject:[self copyUITableViewCell:self.tableViewCell]];
self.tableViewCell = nil;
}
self.tableViewCells = [[NSArray alloc] initWithArray:cells];
} onFail:^(NSString *error, id context) {
NSLog(#"FAIL with error: %#", error);
}];
}
- (void)viewDidUnload
{
[self setTableViewCell:nil];
[self setMyLabel:nil];
[self setMyImage:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void) bindMyModel:(MyModel*)model toView:(UITableViewCell*)view
{
if (view) {
self.myLabel.text = model.myLabelText;
self.myImage.image = model.myImageResource;
self.myLabel = nil;
self.myImage = nil;
}
}
- (UITableViewCell*)copyUITableViewCell:(UITableViewCell*)cell
{
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject: cell];
return [NSKeyedUnarchiver unarchiveObjectWithData: archivedData];
}
#pragma mark - Table view data source
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [self.tableViewCells objectAtIndex:indexPath.row];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.myModel.items.count;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Irrelevant code here
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return ((UITableViewCell*)[self.tableViewCells objectAtIndex:indexPath.row]).frame.size.height;
}
#end
You are trying to use two IBOutlets on your UITableViewController to populate a multitude of UILabels and UIImageViews that are part of the UITableViewCell. You need to create a custom subclass of UITableViewCell and add the IBOutlets to that subclass.
#interface CustomCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#property (weak, nonatomic) IBOutlet UIImageView *myImage;
#end
then in your bindMyModel:toView:
- (void) bindMyModel:(MyModel*)model toView:(CustomCell*)view
{
if (view) {
view.myLabel.text = model.myLabelText;
view.myImage.image = model.myImageResource;
}
}
Now you have independent IBOutlets for each of your Cells. You will also need to change some of your bindings as well. This is a fix, but honestly I would rewrite a lot of the code and just use dequeueReusableCellWithIdentifier in your cellForRowAtIndexPath call, and keep a pool of CustomCells that you will reuse, and just set up the myLabel.text and myImage.image in the cellForRowAtIndexPath call.