Loading a thumbnail image into a UITableView from JSON - ios

I'm having issue trying to load a thumbnail from JSON into a UITableView cell. The cell's UI is a xib file. I'm not able to parse the thumbnail part of the JSON and display it in the table view. It's been a while since I did this (I tend to work on more games than typical iOS apps), and the last time I did it was a slightly different implementation.
JSON:
{
"data" :
[
{
"user_id" : "3",
"username" : "Alex Perez",
"avatar_url" : "http://mywebsite.com/images/alex_avatar.png",
"message" : "Hello there?"
},
{
"user_id" : "4",
"username" : "Jon Doe",
"avatar_url" : "http://mywebsite.com/images/john_avatar.png",
"message" : "I'm here now"
},
{
"user_id" : "2",
"username" : "Sam Givens",
"avatar_url" : "http://mywebsite.com/images/sam_avatar.png",
"message" : "Can we have a meeting around 2?"
},
....
And the data in the Data.h:
#import <Foundation/Foundation.h>
#interface Data : NSObject
#property (nonatomic, readwrite) int user_id;
#property (nonatomic, strong) NSString *username;
#property (nonatomic, strong) NSString *avatar_url;
#property (nonatomic, strong) NSString *message;
- (void)loadWithDictionary:(NSDictionary *)dict;
#end
Data.m:
#import "Data.h"
#implementation Data
- (void)loadWithDictionary:(NSDictionary *)dict {
self.user_id = [[dict objectForKey:#"user_id"] intValue];
self.username = [dict objectForKey:#"username"];
self.avatar_url = [dict objectForKey:#"avatar_url"];
self.message = [dict objectForKey:#"message"];
}
#end
Here is I'm running into issues when declaring the property and assigning the property to the data, so then it can then be passed to the View Controller that is going to display it. I'm getting the compiler warning Incompatible pointer types assigning to UIImage * from NSString*. I don't understand why Xcode isn't complaining about the other properties like the UILabel and the UITextView.
Cell.m
#import "Cell.h"
#interface Cell ()
#property (nonatomic) int userID;
// UIImageView property created from Interface Builder
#property (strong, nonatomic) IBOutlet UIImageView *avatarImage;
#property (nonatomic, strong) IBOutlet UILabel *usernameLabel;
#property (nonatomic, strong) IBOutlet UITextView *messageTextView;
#end
#implementation Cell
- (void)loadWithData:(Data *)data {
self.userID = data.user_id;
// Here I get "Incompatible pointer types assigning to UIImage * from NSString*
self.avatarImage.image = data.avatar_url;
self.usernameLabel.text = data.username;
self.messageTextView.text = data.message;
}
#end
Finally the MessagesViewController where it is displayed:
#interface MessagesViewController ()
#property (nonatomic, strong) IBOutlet UITableView *tableView;
#property (nonatomic, strong) NSMutableArray *loadedChatData;
#end
#implementation MessagesViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.loadedChatData = [[NSMutableArray alloc] init];
[self loadJSONData];
}
- (void)loadJSONData {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"json"];
NSError *error = nil;
NSData *rawData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error];
id JSONData = [NSJSONSerialization JSONObjectWithData:rawData options:NSJSONReadingAllowFragments error:&error];
[self.loadedChatData removeAllObjects];
if ([JSONData isKindOfClass:[NSDictionary class]]) {
NSDictionary *jsonDict = (NSDictionary *)JSONData;
NSArray *loadedArray = [jsonDict objectForKey:#"data"];
if ([loadedArray isKindOfClass:[NSArray class]])
{
for (NSDictionary *chatDict in loadedArray)
{
Data *chatData = [[Data alloc] init];
[chatData loadWithDictionary:chatDict];
[self.loadedChatData addObject:chatData];
}
}
}
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"Cell";
Cell *cell = nil;
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = (Cell *)[nib objectAtIndex:0];
}
Data *data = [self.loadedChatData objectAtIndex:[indexPath row]];
[cell loadWithData:data];
return cell;
}

U have to modify the error line and use it as :
self.avatarImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:data.avatar_url]]];

Create a custom class for the nib and then place the certain code in it to load the image from direct URL ... this works
var stringUrl = "http://mywebsite.com/images/alex_avatar.png"
var url: NSURL = NSURL(string: stringUrl)!;
self.imageView1.sd_setImageWithURL(url, placeholderImage: UIImage(named: "no_image_small.png"));

Try the Below code, it may help you.
NSURL *url = [NSURL URLWithString:#"http://mywebsite.com/images/alex_avatar.png"];
UIImage *thumbnail = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
if (thumbnail == nil) {
thumbnail = [UIImage imageNamed:#"noimage.jpg"] ; //if no image get from url mean show a dummy one
}
CGSize itemSize = CGSizeMake(80, 80); //your own size can replace with 80
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[thumbnail drawInRect:imageRect];
cell.thumbnailImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Related

NSMutableArray object property changes its type and value error

my problem is very strange so i can't search for it
i have a model
#implementation newChatMessage
#synthesize miDProperty = _miDProperty;
#synthesize mUserName = _mUserName;
#synthesize mUID = _mUID;
#synthesize mPhoto = _mPhoto;
#synthesize mDate = _mDate;
#synthesize mText = _mText;
#synthesize SeenBy = _SeenBy;
#end
#interface newChatMessage : NSObject
#property (nonatomic, assign) NSString *miDProperty;
#property (nonatomic, strong) NSString *mDate;
#property (nonatomic, strong) NSString *mText;
#property (nonatomic, strong) NSString *mPhoto;
#property (nonatomic, strong) NSString *mUID;
#property (nonatomic, strong) NSString *mUserName;
#property (nonatomic, strong) NSArray *SeenBy;
#end
then i define an object from data coming from fireBase database
Allmessages = [[NSMutableArray alloc]init];
ref = [[FIRDatabase database]reference];
[[[ref child:#"classes"]child:_classname]observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSEnumerator *children = [snapshot children];
printf("%s", snapshot.key);
FIRDataSnapshot *child;
while (child = [children nextObject]) {
NSDictionary *obj = (NSDictionary*)child.value;
newChatMessage* msg = [[newChatMessage alloc]init];
//NSString *texte = [child ]
msg.miDProperty = [NSString stringWithFormat:#"%#",child.key];//here its run good
msg.mText = [obj objectForKey:#"mText"];
msg.mDate = [obj objectForKey:#"mDate"];
msg.mPhoto = [obj objectForKey:#"mPhoto"];
msg.mUID = [obj objectForKey:#"mUID"];
msg.mUserName = [obj objectForKey:#"mUserName"];
msg.SeenBy = [obj objectForKey:#"SeenBy"];
lastOne = child.key;
[Allmessages addObject:msg];
}
[self.collectionView reloadData];
if (lastOne != nil)
[self lesitner];
}];
this work good and all properties have it's correct value
but after finishing and start to reload collection view iDproperty changes its value and type
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessagesCollectionViewCell *cell = [super collectionView:collectionView cellForItemAtIndexPath:indexPath];//here iDproperty type and value changes
newChatMessage* currentMSG = Allmessages[indexPath.row];
NSLog(#"%ld", (long)indexPath.row);
NSLog(#"%ld", (long)indexPath.item);
[[[[[ref child:#"classes"]child:_classname]child:currentMSG.miDProperty]child:#"SeenBy"]setValue:[self senderId]];
return cell;
}
my problem was in defining nsstring as assign
althaugh it have to be strong
#property (nonatomic, strong) NSString *miDProperty;

iOS: How can i get location names of multiple longitudes and latitudes when data is coming from web service as a response?

I need to help with my code. I am getting longitudes and latitudes as a response from a web service. I need to convert them to a location name and show it in respective table view cell label.
Following are the response, code and screen shot of my view where I show my converted city, country name, and correct my code where i am doing mistake.
#import <UIKit/UIKit.h>
#import "JobTableViewCell.h"
#import "SlideNavigationController.h"
#import <CoreLocation/CoreLocation.h>
#interface JobPostedViewController : UIViewController <SlideNavigationControllerDelegate, UITableViewDataSource, CLLocationManagerDelegate>
#property (strong, nonatomic) NSArray* job_id;
#property (strong, nonatomic) NSArray* assigned_user_id;
#property (strong, nonatomic) NSArray* job_title;
#property (strong, nonatomic) NSArray* job_description;
#property (strong, nonatomic) NSArray* job_priority;
#property (strong, nonatomic) NSString* job_longitude;
#property (strong, nonatomic) NSArray* date;
#property (strong, nonatomic) NSString* job_latitude;
#property (strong, nonatomic) NSArray* job_completed;
#property (strong, nonatomic) NSArray* job_start_date;
#property (strong, nonatomic) NSArray* bids;
#property (nonatomic, strong) CLGeocoder *myGeocoder;
- (IBAction)onClickJobButton:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *sideNavigation;
#property (weak, nonatomic) IBOutlet UITableView *jobPostedTableView;
#end
`
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.jobPostedTableView.dataSource = self;
//Slide Navigation
[self.sideNavigation addTarget:[SlideNavigationController sharedInstance] action:#selector(toggleLeftMenu) forControlEvents:UIControlEventTouchUpInside];
WebManager *manager = [WebManager sharedInstance];
[manager getJobPostedWithCompletionBlock:^(id response){
NSDictionary *dictionary = (NSDictionary *)response;
// Read data from JSON
NSDictionary *responseObject = [dictionary objectForKey:#"response"];
NSLog(#"The Array%#",responseObject);
self.bids = [responseObject objectForKey:#"bids"];
self.job_description = [responseObject objectForKey:#"job_description"];
self.job_id = [responseObject objectForKey:#"job_id"];
self.job_completed = [responseObject objectForKey:#"job_completed"];
self.job_latitude = [responseObject objectForKey:#"job_latitude"];
self.job_longitude = [responseObject objectForKey:#"job_longitude"];
self.job_priority = [responseObject objectForKey:#"job_priority"];
self.job_start_date = [responseObject objectForKey:#"job_start_date"];
self.job_title = [responseObject objectForKey:#"job_title"];
[self.jobPostedTableView reloadData];
}];
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:[self.job_latitude floatValue] longitude:[self.job_longitude floatValue]]; //insert your coordinates
[ceo reverseGeocodeLocation:loc
completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"placemark %#",placemark);
//String to hold address
[[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
NSLog(#"addressDictionary %#", placemark.addressDictionary);
NSArray *ar = [placemark.addressDictionary objectForKey:#"locality"];
NSLog(#"placemark %#",ar); // Extract the city name
NSLog(#"placemark %#",placemark.country); // Give Country Name
}
];
}
#pragma mark - SlideNavigationController Methods
- (BOOL)slideNavigationControllerShouldDisplayLeftMenu
{
return YES;
}
#pragma mark - TableView Data Source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.job_title count];
}
- (NSInteger) numberOfSectionsInTableview:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"JobTableViewCell";
JobTableViewCell *cell = (JobTableViewCell *)[self.jobPostedTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil) {
cell = [[JobTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
// Comparing array string to display an urgent image
if ([[self.job_priority objectAtIndex:indexPath.row]
isEqualToString:#"urgent"]) {
cell.urgentLabel.hidden = NO;
} else {
cell.urgentLabel.hidden = YES;
}
// Condition whether job completed is open or closed
if ([[self.job_completed objectAtIndex:indexPath.row]
isEqualToString:#"1"]) {
cell.jobStatus.text = #"Open";
[cell.jobStatus setTextColor:[UIColor colorWithRed:(84/255.f) green:(56/255.f) blue:(255/255.f) alpha:1.0f]];
cell.flagImage.image = [UIImage imageNamed:#"jobPosted_opened.PNG"];
} else {
cell.jobStatus.text = #"Closed";
[cell.jobStatus setTextColor:[UIColor colorWithRed:(179/255.f) green:(179/255.f) blue:(180/255.f) alpha:1.0f]];
cell.flagImage.image = [UIImage imageNamed:#"jobPosted_closed.PNG"];
}
cell.jobTitle.text = [self.job_title objectAtIndex:indexPath.row];
cell.jobContent.text = [self.job_description objectAtIndex:indexPath.row];
cell.bidsLabel.text = [[self.bids objectAtIndex:indexPath.row ]stringValue];
return cell;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
Here's the solution:
Change NSString to NSArray of these properties:
#property (strong, nonatomic) NSString* job_longitude;
#property (strong, nonatomic) NSString* job_latitude;
Add a new property to hold the geocode results:
#property (strong, nonatomic) NSMutableDictionary* reversedGeocodes;
Set reversedGeocodes in viewDidLoad: method:
self.reversedGeocodes = [NSMutableDictionary dictionary];
Add this method to get the reversed geoCode (and save it for the future):
- (void)locationNameWithLat:(float)lat
lng:(float)lng
completionHandler:(void (^)(NSString *locationName, NSError *error))completion
{
if (!lat || !lng)
completion(#"Unknown location", nil);
if (!completion || !lat || !lng)
return;
NSString *latStr = #(lat).description;
NSString *lngStr = #(lng).description;
// For each pair of lat and lng creating a unique key and saving the result
// so we don't have to process the same pair multiple times.
// Example:
// lat = 23.039567; lng = 72.566004;
// key = #"23.03956772.566004"; value would be whatever CoreLocation returns
NSString *key = [latStr stringByAppendingString:lngStr];
if (key.length) {
if ([self.reversedGeocodes[key] length]) {
completion (self.reversedGeocodes[key], nil);
} else {
self.reversedGeocodes[key] = #"Loading...";
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *location = [[CLLocation alloc] initWithLatitude:lat longitude:lng];
[geocoder reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
completion(#"Unknown location", error);
} else {
CLPlacemark *placemark = placemarks.firstObject;
NSString *locationName = placemark.country; // Default = country
if (placemark.locality.length) // add city if available
locationName = [NSString stringWithFormat:#"%#, %#", placemark.locality, placemark.country];
self.reversedGeocodes[key] = locationName.length ? locationName : #"Unknown location";
completion(self.reversedGeocodes[key], nil);
}
}
];
}
} else {
completion(#"Unknown location", nil);
}
}
Call the above method from cellForRowAtIndexPat: method before your return the cell:
float lat = self.job_latitude[indexPath.row];
float lng = self.job_longitude[indexPath.row];
[self locationNameWithLat:lat
lng:lng
completionHandler:^(NSString *locationName, NSError *error) {
cell.locationName.text = locationName;
}];
return cell;
P.S. Let me know if I missed anything or misspelled because I typed some of the code on here...

Cells disappear when scroll down in my UITableView

When I scroll down in my tableView some contents of cells disappear (labels and imageViews).
My code:
-(void)viewWillAppear:(BOOL)animated{
[comentarios removeAllObjects];
NSString *lookup=[NSString stringWithFormat:#"http://my.url"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:lookup]];
[request setHTTPMethod:#"GET"];
NSError *error = nil; NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSMutableArray *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"%#",jsonDict);
for (int i=0; i<[jsonDict count]; i++) {
Comentario *come=[[Comentario alloc] init];
come.nick=[[jsonDict objectAtIndex:i] objectForKey:#"nick"];
come.comment=[[jsonDict objectAtIndex:i] objectForKey:#"content"];
come.avatar=[[jsonDict objectAtIndex:i] objectForKey:#"color"];
[comentarios addObject:come];
}
[self reloadInputViews];
[self.comentariosTableView reloadData];
}
and
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if( cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: CellIdentifier];
}
// Display recipe in the table cell
UIImageView *avatar = (UIImageView *)[cell viewWithTag:100];
avatar.image = [UIImage imageNamed:[[comentarios objectAtIndex:indexPath.row] avatar]];
UILabel *nick = (UILabel *)[cell viewWithTag:101];
nick.text =[[comentarios objectAtIndex:indexPath.row] nick];
UILabel *comment = (UILabel *)[cell viewWithTag:102];
comment.text = [[comentarios objectAtIndex:indexPath.row] comment];
UIButton *sinvoto = (UIButton *)[cell viewWithTag:103];
UIButton *ticket = (UIButton *)[cell viewWithTag:104];
return cell;
}
I can't see the mistake, please help me.
Thank you in advance
EDIT Nª1
just changed this
ViewController.m
#import "ViewController.h"
#import "SimpleTableCell.h"
#interface ViewController (){
NSMutableArray *comentarios;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.comenatrioTableView.delegate=self;
self.comenatrioTableView.dataSource=self;
self.automaticallyAdjustsScrollViewInsets = NO;
UIImage *plus=[[UIImage imageNamed:#"megafono.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc] initWithImage:plus style:UIBarButtonItemStylePlain target:self action:#selector(comenta:)];
self.navigationController.navigationBar.barTintColor=[UIColor colorWithRed:204.0/255.0 green:0.0/255.0 blue:00.0/255.0 alpha:1.0f];
comentarios=[[NSMutableArray alloc] init];
[self reloadInputViews];
}
-(void)viewWillAppear:(BOOL)animated{
[comentarios removeAllObjects];
NSString *lookup=[NSString stringWithFormat:#"http://myURL"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:lookup]];
[request setHTTPMethod:#"GET"];
NSError *error = nil; NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSMutableArray *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"%#",jsonDict);
for (int i=0; i<[jsonDict count]; i++) {
Comentario *come=[[Comentario alloc] init];
come.nick=[[jsonDict objectAtIndex:i] objectForKey:#"nick"];
come.comment=[[jsonDict objectAtIndex:i] objectForKey:#"content"];
come.avatar=[[jsonDict objectAtIndex:i] objectForKey:#"color"];
[comentarios addObject:come];
}
[self reloadInputViews];
}
-(void)viewDidAppear:(BOOL)animated{
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [comentarios count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 110;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier forIndexPath:indexPath];
Comentario *comentario=[[Comentario alloc] init];
comentario =[comentarios objectAtIndex:indexPath.row];
cell.avatar.image=[UIImage imageNamed:[comentario avatar]];
cell.nick.text=[comentario nick];
cell.comment.text =[comentario comment];
return cell;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
-(void)comenta:(id)sender{
[self performSegueWithIdentifier:#"goComment" sender:self];
}
#end
and ViewController.h
#import <UIKit/UIKit.h>
#import "Comentario.h"
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *comenatrioTableView;
#end
Edit Nª3
The proble is when I scroll down, the information of cells become nil but comentarios Array have the information.
Edit Nª4
here is the project https://github.com/QuimeraKoke/BANG-
I have a couple of other suggestions that will improve your code.
You have to call super in viewDidAppear and viewWillAppear methods:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
}
Instead of using:
Comentario *comentario = [[Comentario alloc] init];
comentario = [comentarios objectAtIndex:indexPath.row];
with:
Comentario *comentario = [comentarios objectAtIndex:indexPath.row];
Finally, you should check your dataSource:
for (int i=0; i<[jsonDict count]; i++) {
Comentario *come = [[Comentario alloc] init];
come.nick = [[jsonDict objectAtIndex:i] objectForKey:#"nick"];
come.comment = [[jsonDict objectAtIndex:i] objectForKey:#"content"];
come.avatar = [[jsonDict objectAtIndex:i] objectForKey:#"color"];
[comentarios addObject:come];
NSLog(#"nick = %#, comment = %#, avatar = %#", come.nick, come.comment, come.avatar);
}
EDIT:
Instead of using:
#interface Comentario : NSObject
#property (weak,nonatomic) NSString *nick;
#property (weak,nonatomic) NSString *comment;
#property (weak,nonatomic) NSString *avatar;
#end
you should use:
#interface Comentario : NSObject
#property (copy,nonatomic) NSString *nick;
#property (copy,nonatomic) NSString *comment;
#property (copy,nonatomic) NSString *avatar;
#en
Your problem has been resolved.
Copy
copy is required when the object is mutable. Use this if you need the
value of the object as it is at this moment, and you don't want that
value to reflect any changes made by other owners of the object. You
will need to release the object when you are finished with it because
you are retaining the copy.
Weak
weak is similar to strong except that it won't increase the reference
count by 1. It does not become an owner of that object but just holds
a reference to it. If the object's reference count drops to 0, even
though you may still be pointing to it here, it will be deallocated
from memory.
This is a good website to learn about strong and weak for iOS 5.
http://www.raywenderlich.com/5677/beginning-arc-in-ios-5-part-1
In addition to the above problem,your constrains of the SimpleTableCell is also incorrect:
You should go to the Main.storyboard and check it.(In Interface Builder Select the Compact Width and Compact Height Size Class)
The tableView:cellForRowAtIndexPath: code you're using is pretty old.
I'd suggest creating a custom UITableViewCell class, with properties for your labels, image, and buttons.
#interface MyTableViewCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *nick;
#property (nonatomic, weak) IBOutlet UILabel *comment;
#property (nonatomic, weak) IBOutlet UIImageView *avatar;
#property (nonatomic, weak) IBOutlet UIButton *sinvoto;
#property (nonatomic, weak) IBOutlet UIButton *ticket;
#end
In your storyboard, set that cell's class to your custom tableViewCell, and connect its IBOutlets to the storyboard cell's labels, image, and buttons. This will eliminate having to use tags.
Change the dequeueReusableCellWithIdentifier: call to:
MyTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
This will always return a cell, so you will never have to check for nil.
Now you can directly set the cell's properties:
cell.avatar.image = [UIImage imageNamed:[[comentarios objectAtIndex:indexPath.row] avatar]];
cell.nick.text =[[comentarios objectAtIndex:indexPath.row] nick];
cell.comment.text = [[comentarios objectAtIndex:indexPath.row] comment];
Update:
This line (has to do with changing the keyboard) is unnecessary and can be removed:
[self reloadInputViews];
Is there a reason why you are using a UIViewController (with a tableView that you added), instead of simply using a UITableViewController?
The UITableViewController knows how to adjust its insets to account for top and bottom bars (and you would set its automaticallyAdjustsScrollViewInsets to YES).
After making the changes that Banning suggests, you may be ok. I can't see any other reason why the cells would be blank after scrolling.
If it's still happening, you should post your Comentario class, so we can see if an issue with that code is affecting the stored data.

UITableViewCells don't take custom value

I'm trying to make an item feed with a UITableView and some JSON objects,
but when I try filling an instance of my custom cell with the JSON data, the UILabels won't change their text.
The JSON has been tested and works. It goes through the loop and creates the right amount of rows. But the text isn't changing to the text from the JSON file.
Here's my code:
feed.m
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *FeedURL = [NSURL URLWithString:#"http://www.personeelsapp.jordivanderhek.com/company/bijcasper/nieuws.json"];
NSData *jsonData = [NSData dataWithContentsOfURL:FeedURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSLog(#"%#", dataDictionary);
self.posts = [NSMutableArray array];
PostsArray = [dataDictionary objectForKey:#"feed"];
for (NSDictionary *bpdDictionary in PostsArray) {
// make new post object
FeedPosts *posts = [FeedPosts InitPost];
NSLog(#"feed check %#" ,[bpdDictionary objectForKey:#"name"]);
posts.postTitle = [bpdDictionary objectForKey:#"name"];
posts.postProfilepic = [bpdDictionary objectForKey:#"profilePic"];
posts.postDatum = [bpdDictionary objectForKey:#"timeStamp"];
posts.postMessage = [bpdDictionary objectForKey:#"status"];
posts.postImage = [bpdDictionary objectForKey:#"image"];
[self.posts addObject:posts];
}
}
[…]
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section {
return [self.posts count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Cellindentifier = #"PostCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Cellindentifier forIndexPath:indexPath];
// Configure the cell...
FeedPosts *posts = [self.posts objectAtIndex:indexPath.row];
cell.postTitle.text = #"test title";
cell.postDatum.text = posts.postDatum.text;
cell.postMessage.text = posts.postMessage.text;
return cell;
}
}
FeedPosts.h
#property (strong, nonatomic) IBOutlet UILabel *postTitle;
#property (strong, nonatomic) IBOutlet UILabel *postMessage;
#property (strong, nonatomic) IBOutlet UIImageView *postImage;
#property (strong, nonatomic) IBOutlet UIImageView *postProfilepic;
#property (strong, nonatomic) IBOutlet UILabel *postDatum;
// designated init
+ (id) InitPost;
FeedPosts.m
+ (id) InitPost {
// init new feed item
return [[self alloc]init];
}
have been getting the following error:
-[__NSCFString text]: unrecognized selector sent to instance
What am I doing wrong?
You have declared several UILabels in FeedPosts.
#property (strong, nonatomic) IBOutlet UILabel *postTitle;
In the following code, you assign NSString (text) to the label object:
FeedPosts *posts = [FeedPosts InitPost];
NSLog(#"feed check %#" ,[bpdDictionary objectForKey:#"name"]);
posts.postTitle = [bpdDictionary objectForKey:#"name"];
Instead, you should set the text for those labels:
posts.postTitle.text = [bpdDictionary objectForKey:#"name"];
Same goes for postMessage and postDatum.

Variable is disappearing when certain functions are called

I'm kind of a noob so hopefully this isn't too complex. I'm having a problem with my code that has so far stumped and confused me and some other users. I spent some time cleaning my code, and following some tutorials, but I still get past this issue. I just know it is something really simple, so here goes:
Im making an iOS app for my blog site. It goes to the site, pulls an XML document (containing the blog title, brief description, and full article url), and parses it to display in a UITableView. To manage this, there are two custom objects: "PostList", and "Post". Post is just an object that hold the individual post data (url, title, publication date, etc) and PostList has an array that holds the Post objects, as well as some getter/setter/init functions.
That all works well. The view loads and the XML is parsed and displays in the list. The problem arises when the user either taps on a link or scrolls some cells off the screen. As far as I can tell, these are both related to the same problem. In the case of the user tapping on the cell, the view controller does not pass a value to the detailed view controller (prepareForSegue), and in the case of scrolling, the cellForRowAtIndexPath does not reinitialize the cell values.
I believe that this is al due to the same problem, that once the view has been initialized, the existing values in the PostList array are somehow deleted. The debugger says the array still sees objects inside it, but they are all blank objects. I have spent forever trying to figure out why.
If you could give me some ideas why this is happening that would be AMAZING! My code is below. I posted almost all of it since Ive had issues with not posting enough before. Hope this helps. If you need more please ask!
-Thanks in advance ;)
FirstViewController.h
#import <UIKit/UIKit.h>
#import "PostList.h"
#import "Post.h"
#interface FirstViewController : UITableViewController
#property (nonatomic, strong) PostList *postController;
#property (nonatomic, strong) IBOutlet UITableView *tableView;
#property (nonatomic, strong) Post *postToSendToDetailView;
#property (nonatomic, strong) NSString *type;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "DetailViewController.h"
#import "Post.h"
#import "PostList.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.type = #"blog";
self.postController = [[PostList alloc] initWithType:self.type];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.postController countOfList];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Post *postAtSighting = [self.postController objectInListAtIndex:indexPath.row];
// Configure the cell...
[[cell textLabel] setText:postAtSighting.name];
[[cell detailTextLabel] setText:postAtSighting.content];
NSLog(#"Cell Initalized");
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"pushToDetailView"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
DetailViewController *destViewController = segue.destinationViewController;
destViewController.aPost = [self.postController objectInListAtIndex:indexPath.row];
}
}
#end
PostList.h
#import <Foundation/Foundation.h>
#import "Post.h"
#interface PostList : NSObject
-(NSMutableArray *) getPostsofType:(NSString *)type;
-(NSString *) getName: (Post *)aPost;
-(NSUInteger) countOfList;
-(Post *)objectInListAtIndex:(NSUInteger)theIndex;
-(id)initWithType:(NSString *)type;
#property (nonatomic, strong) NSMutableArray *postsArray;
#property (nonatomic) NSString *urlString;
#property (nonatomic) NSUInteger countingIndex;
#end
PostList.m
#import "PostList.h"
#import "TBXML+HTTP.h"
#implementation PostList
- (id)initWithType:(NSString *)type {
self = [super init];
if (self) {
//Creates postArray to store Post objects
self.postsArray = [[NSMutableArray alloc] init];
//Create other resources
self.urlString = [[NSString alloc] init];
self.countingIndex = 0;
[self getPostsofType:type];
}
return self;
}
-(NSString *)getName:(Post *)somePost {
//Gets the Name of the Post object and returns the value
NSString *name = somePost.name;
return name;
}
-(NSMutableArray *)getPostsofType:(NSString *)type {
//Go to the Server and get the posts that are available for the post type selected.
//Determing the post type
if ([type isEqual: #"blog"]) {
self.urlString = #"http://www.biteofanapple.com/blog/feeds/blogFeed.xml";
}
if ([type isEqual: #"bbp"]) {
self.urlString = #"http://www.biteofanapple.com/blog/feeds/blogFeed.xml";
}
//Checks for an existant xmlBlogData.xml
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSString* blogXML = [documentsDirectory stringByAppendingPathComponent:#"xmlBlogData.xml"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:blogXML];
NSData *data = [[NSData alloc] init];
//Determines the best way to handle the xml file
if (fileExists) {
data = [NSData dataWithContentsOfFile:blogXML];
} else {
NSURL *url = [NSURL URLWithString:self.urlString];
//Goes to the Server and reads the XML file of the Posts
data = [NSData dataWithContentsOfURL:url];
if (data != nil) {
NSLog(#" NSData value is not nil");
}
//Saves the XML data to a .dat file in the document's directory
NSError *error;
BOOL succeed = [data writeToFile:[documentsDirectory stringByAppendingPathComponent:#"xmlBlogData.dat"] atomically:YES];
if (!succeed){
// Handle error here
NSLog(#"Error: File was unable to be written to the documents directory.");
[error setValue:#"-1" forKey: #"File unable to be written"];
}
}
//Parses the XML file
TBXML *tbxml = [TBXML newTBXMLWithXMLData:data error:nil];
//Prints the data Variable to NSLog
NSLog(#"%#", [NSString stringWithUTF8String:[data bytes]]);
//Make some placeholder variables
if (tbxml.rootXMLElement == nil) {
NSLog(#"XML Document does not have rootElement. Error -1");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry, there was an error" message:#"Could not find root XML element. Please contact support for help with this issue." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
TBXMLElement *element = tbxml.rootXMLElement;
TBXMLElement *nextElement = element->nextSibling;
NSLog(#"URLs have been set, preparing for parse/input. [PostList.getPosts]");
//Extracts the content of the XML file and saves it to values in the Post Class
do {
/**********
* This loop goes through the XML file looking for <item> tags that hold information
* about the blog posts. It finds <item> tags and scours them for <title>, <description>,
* <pubdate>, and <link> tags to put into the class variables for the Post Class (aPost).
**********/
NSString *stringElement = [TBXML elementName:element];
NSLog(#"%#", stringElement);
//Creates Post variable to put stuff in.
Post *aPost = [[Post alloc] init];
//Sorts through the header junk to find the first <item> tag.
if (![stringElement isEqualToString:#"item"]) {
if (!(element->firstChild)) {
if (!(element->nextSibling)) {
element = nil;
}
element = element->nextSibling;
}
element = element->firstChild;
}
//Once the first <item> tag is found, this code executes.
else {
//Now we move to the first child tag and scour its contents and its siblings
nextElement = [TBXML nextSiblingNamed:#"item" searchFromElement:element];
element = element->firstChild;
do {
//Here it loops over and over until all the parts have been collected.
stringElement = [TBXML elementName:element];
if ([stringElement isEqualToString:#"title"]) {
aPost.name = [TBXML textForElement:element];
}
if ([stringElement isEqualToString:#"description"]) {
aPost.content = [TBXML textForElement:element];
}
if ([stringElement isEqualToString:#"link"]) {
aPost.postURL = [TBXML textForElement:element];
}
if ([stringElement isEqualToString:#"pubdate"]) {
aPost.publicationDate = [TBXML textForElement:element];
}
element = element->nextSibling;
} while (element->nextSibling);
NSLog(#"%#", [self getName:aPost]);
NSLog(#"name %# content %#", aPost.name, aPost.content);
[self.postsArray insertObject:aPost atIndex:self.countingIndex];
self.countingIndex++;
element = nextElement;
}
} while ((element != nil));
return self.postsArray;
}
-(Post *)objectInListAtIndex:(NSUInteger)theIndex {
return [self.postsArray objectAtIndex:theIndex];
}
-(NSUInteger)countOfList {
return [self.postsArray count];
}
#end
Post.h
#import <Foundation/Foundation.h>
#class Post;
#interface Post : NSObject
#property (nonatomic, weak) NSString *name;
#property (nonatomic, weak) NSString *author;
#property (nonatomic, weak) NSString *publicationDate;
#property (nonatomic, weak) NSString *content;
#property (nonatomic, weak) NSString *postURL;
#end
Post.m
#import "Post.h"
#implementation Post
- (id)init {
self = [super init];
if (self) {
self.name = #"";
self.author = #"";
self.content = #"";
self.publicationDate = #"";
self.postURL = #"";
}
return self;
}
#end
As I posted in the comment above, the problem is you are using weak references in your Post class. Try this code instead:
#import <Foundation/Foundation.h>
#class Post;
#interface Post : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *author;
#property (nonatomic, strong) NSString *publicationDate;
#property (nonatomic, strong) NSString *content;
#property (nonatomic, strong) NSString *postURL;
#end
If you want to learn about the differences between strong and weak references, take a look at this question:
Differences between strong and weak in Objective-C
Also note that the default reference type for objective-c properties is strong, so you can omit the strong keyword if you wish.

Resources