ios: load new data into UICollectionView - ios

I want to make a application which will display images into UICollectionView.
Images will be downloaded from server and then shows into collectionView.
I am using custom collectionView layout into xib file.
At a time, 20 images is receiving from server.
Problem: I can't show newly downloaded images into collectionView.
Here is my code:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
BOOL reloaded = NO;
static NSString *cellIdentifier = #"cvCell";
CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
NSMutableArray *data = [self.dataArray objectAtIndex:indexPath.section];
NSString *cellData = [data objectAtIndex:indexPath.row];
dispatch_queue_t queue = dispatch_queue_create("com.justTest.anotherSingleApplication", NULL);
dispatch_async(queue, ^{
//code to be executed in the background
NSString *imageName1 = [[NSString alloc]initWithFormat:#"http://www.abc.com/images/thumb/%#", cellData];
NSString *url_Img1 = imageName1;
UIImage *aImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url_Img1]]];
dispatch_async(dispatch_get_main_queue(), ^{
//code to be executed on the main thread when background task is finished
[cell.cellImage setImage:aImage];
});
});
if (indexPath.row == self.imageArray.count - 1 && !reloaded) {
getOnScrollImages *getImage = [[getOnScrollImages alloc] init]; // class to get image name from server
NSMutableArray *astring = (NSMutableArray *)[getImage getImageNameFromServer:#"list" board:#"111" pin:#"122345"]; // method to get image name from server
[self setNewTestArray:astring]; //adding newly downloaded image name into array
reloaded = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
}
return cell;
}
Any suggestion please?
NOTE: I am just starting developing iOS application, this may be a very silly question.

Use asynchronously fetch to get data from server and display it in collectionView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
YourDataModel *model = self.dataArray[indexPath.row];
YourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
if ([self checkWhetherImageAlreadyExist]) {
[cell.imageView setImage:model.image];
} else {
//show placeholder to avoid nothing in your UI, or your user gets confused
[cell.imageView setImage:placeholderImage];
[self startDownloadImageForIndexPath:indexPath];
}
}
- (void)startDownloadImageForIndexPath:(NSIndexPath *)indexPath
{
//YourImageDownloader is a class to fetch data from server
//imageDownloadsInProgress is a NSMutableDictionary to record the download process, which can avoid repeat download
YourImageDownloader *downloader = [self.imageDownloadsInProgress objectForKey:indexPath];
if (downloader == nil) {
YourDataModel *model = self.dataArray[indexPath.row];
//configure downloader
downloader = [[YourImageDownloader alloc] init];
[downloader setURL:model.url];
[downloader setCompletionHandler:^{
//download the image to local, or you can pass the image to the block
model.image = [UIImage imageWithContentsOfFile:model.localPath];
YourCell *cell = [self.mCollectionView cellForItemAtIndexPath:indexPath];
[cell.imageView setImage:model.image];
//remove downloader from dictionary
[self.imageDownloadsInProgress removeObjectForKey:indexPath];
}];
//add downloader to dictionary
[self.imageDownloadsInProgress setObject:downloader forKey:indexPath];
//start download
[downloader startDownload];
}
}
Use a class to download the image. If you have many images in one collection view, you may consider to save these images to local in case of memory warning. if now many, just leave the image in memory and display it in your collection view.
the code followed is save the image to local and read image data from local when displaying.
in .h:
#import <Foundation/Foundation.h>
#interface PortraitDownloader : NSObject
#property (nonatomic, copy) NSString *portraitName;
#property (nonatomic, copy) void (^completionHandler)(void);
- (void)startDownload;
- (void)cancelDownload;
#end
in .m
#import "PortraitDownloader.h"
#import <CFNetwork/CFNetwork.h>
#import "NSString+ImagePath.h" // it's a category to get the image local path
#interface PortraitDownloader ()
#property (nonatomic, strong) NSMutableData *activeDownload;
#property (nonatomic, strong) NSURLConnection *portraitConnection;
#end
#implementation PortraitDownloader
- (void)startDownload
{
self.activeDownload = [NSMutableData data];
NSString *urlstr = [NSString serverPortraitPathWithPortrait:self.portraitName];
NSURL *url = [NSURL URLWithString:urlstr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.portraitConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)cancelDownload
{
[self.portraitConnection cancel];
self.portraitConnection = nil;
self.activeDownload = nil;
}
#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Clear the activeDownload property to allow later attempts
self.activeDownload = nil;
// Release the connection now that it's finished
self.portraitConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// save to local path
NSString *localSavePath = [NSString localPortraitPathWithPortrait:self.portraitName];
[self.activeDownload writeToFile:localSavePath atomically:YES];
self.activeDownload = nil;
// Release the connection now that it's finished
self.portraitConnection = nil;
// call our delegate and tell it that our icon is ready for display
if (self.completionHandler) {
self.completionHandler();
}
}
#end
if you want to leave your image in-memory, just modify the completion block as:
in .h
typedef void (^Completion_handle) (UIImage *image);
#interface PortraitDownloader : NSObject
#property (nonatomic, copy) Completion_handle myCompletionBlock;
and in .m
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// get image from data
UIImage *image = [UIImage imageWithData:self.activeDownload];
self.activeDownload = nil;
// Release the connection now that it's finished
self.portraitConnection = nil;
// call our delegate and tell it that our icon is ready for display
if (self.myCompletionBlock) {
self.myCompletionBlock(image);
}
}
and also modify methods startDownloadImageForIndexPath, save the image to your model to retain it

This method expects to have answers immediately:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
when your code doesn't respond fast enough to it, the app will usually display nothing, or sometimes just crash (depending on what you've setup)
A common design pattern is to store the info that will be supplied to the collectionView in a class variable (it doesn't have to be a property, but it often times is). You always store SOMETHING in that variable, even if it is old or stale data.
Then you have the methods defined in the UICollectionViewDataSource protocol pull what they need directly from the class variables, with no delay.
Other methods can fetch and retrieve and sling updated data around, and once they finish you call reloadData: on the collectionView to update the interface.
assuming the asynchronous calls you are using are successfully retrieving data eventually, they are probably too slow for what the UICollectionViewDataSource protocol methods are expecting.
A suggestion for how to get started would be to move the code fetching your data to separate methods, and then stage the data in a class variable or two which the collectionView can reliably draw from.
You can try it with static data loaded into the bundle at first if you need, and then move into asynchronous pulls from the web too.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
UIImageView *imgView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"profile_pic.png"]];
NSMutableDictionary *contactData=[NSMutableDictionary new];
contactData = [self.collectionData objectAtIndex:indexPath.row];
imgView.image=[contactData objectForKey:#"image"];
[cell addSubview:imgView];
return cell;
}

Related

How to avoid cell duplicate values in tableview/collectionview in iOS?

I want to avoid tableview/collectionview cells with duplicate values.
Here is my code :
NSURL *imageURL = [NSURL URLWithString:[finalImage objectAtIndex:indexPath.row]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (nonatomic, strong) NSArray *imagesArray; //Array of URL for images
#property (nonatomic, strong) NSMutableDictionary *dataDictionary; // Using to store downloaded data
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//Some images for test
self.imagesArray = #[#"https://cdn.pixabay.com/photo/2017/05/31/18/38/sea-2361247__480.jpg", #"https://cdn.pixabay.com/photo/2017/06/02/11/49/still-life-2366084__480.jpg", #"https://cdn.pixabay.com/photo/2017/06/04/20/31/sheep-2372148__480.jpg", #"https://cdn.pixabay.com/photo/2017/06/04/15/08/architecture-2371294__480.jpg", #"https://cdn.pixabay.com/photo/2017/05/18/21/54/tower-bridge-2324875__480.jpg", #"https://cdn.pixabay.com/photo/2017/05/16/21/24/gorilla-2318998__480.jpg", #"https://cdn.pixabay.com/photo/2017/05/24/11/40/desert-2340326__480.jpg", #"https://cdn.pixabay.com/photo/2017/05/21/15/14/balloon-2331488__480.jpg", #"https://cdn.pixabay.com/photo/2017/05/19/15/16/countryside-2326787__480.jpg", #"https://cdn.pixabay.com/photo/2017/04/09/09/56/avenue-2215317__480.jpg"];
self.tableView.dataSource = self;
self.tableView.delegate = self;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
self.dataDictionary = [NSMutableDictionary new];
}
- (void)asyncImageForIndexPath: (NSIndexPath *)indexPath onCompletion: (void(^)(UIImage *image))completionBlock {
NSURL *imageURL = [NSURL URLWithString:[self.imagesArray objectAtIndex:indexPath.row]];
if ([self.dataDictionary objectForKey:[NSString stringWithFormat:#"%ld", (long)indexPath.row]]) {
completionBlock([UIImage imageWithData:[self.dataDictionary objectForKey:[NSString stringWithFormat:#"%ld", (long)indexPath.row]]]);
}
//Sending async request not to block main thread and storing it into the dictionary
//After storing, reloading table view on main thread. So the function is called again, but as we have stored NSData for image, method won't send request
[[[NSURLSession sharedSession] dataTaskWithURL:imageURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(!error) {
[self.dataDictionary setObject:data forKey:[NSString stringWithFormat:#"%ld", indexPath.row]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
}] resume];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 250;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.imagesArray.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
//Downloading image separated into another method
[self asyncImageForIndexPath:indexPath onCompletion:^(UIImage *image) {
cell.imageView.image = image;
}];
return cell;
}
Try out the code, and let me know if that helps. If you have any questions, feel free to ask

FullScreen Image in UICollectionView on cell tap

I am using SDWebImage to show image in UICollectionView. I am getting productImageUrl and productId as server response. Able to show the image in Custom-cell, now what I want is:
1) Display the image in large view with a UIButton(buyButton) on another UIViewController named ProductDetailViewController.(Image is showing on the ProductDetailViewController but the way i am passing image url from ProductCollectionViewController is not right I think, please review the code and suggest me some better way to do it )
2) On button click a call will be made to the server with the productId which I got earlier as Server Response.(How would I pass the dictId to ProductDetailViewController so that I can make a call to the server).
3) Getting only two key-value of an Object as response, so its ok to parse it in multiple dictionary for multiple value. But If the response contain multiple value, what will be the optimized way to parse the response.
Here is the code which i have tried.
(Sorry for long unoptimized code, still in learning phase)
ProductCollectionViewController.m
#import "ProductCollectionViewController.h"
#import "ProductCell.h"
#import "UIImageView+WebCache.h"
#import "ProductDetailViewController.h"
#interface ProductCollectionViewController ()
#property(strong, nonatomic) NSMutableArray *productList;
#end
#implementation ProductCollectionViewController
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
static NSString * const reuseIdentifier = #"Cell";
-(void)viewDidLoad
{
[super viewDidLoad];
[self getProductList];
}
-(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)getProductList
{
NSURL * url = [NSURL URLWithString:#"xxxx.yyyy.zzzz"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject];
NSURLSessionDataTask * dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if (!error)
{
NSDictionary *responseJson = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSArray *rsBody = responseJson[#"rsBody"];
_productList = [NSMutableArray new];
for(NSDictionary *dict in rsBody)
{
NSMutableDictionary *dictUrl=[[NSMutableDictionary alloc]init];
NSMutableDictionary *dictProductId =[[NSMutableDictionary alloc]init];
[dictUrl setValue:[dict valueForKey:#"productImageUrl"] forKey:#"url"];
[dictId setValue:[dict valueForKey:#"productId"] forKey:#"id"];
[_productList addObject:dictUrl];
[_productList addObject:dictId];
}
NSLog(#"urls for image: %#",_productList );
[self.collectionView reloadData];
}}];
[dataTask resume];
}
#pragma mark <UICollectionViewDataSource>
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _productList.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ProductCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
NSURL *imageUrl = [[_productList objectAtIndex:indexPath.row]valueForKey:#"url"];
[cell.productImageView sd_setImageWithURL:imageUrl placeholderImage:[UIImage imageNamed:#"placeholder.jpg"]];
NSString *id =[[_productList objectAtIndex:indexPath.row] valueForKey:#"id"];
cell.productPrice.text= id;
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showProduct"]) {
NSArray *indexPaths = [self.collectionView indexPathsForSelectedItems];
ProductDetailViewController *destViewController = segue.destinationViewController;
NSIndexPath *indexPath = [indexPaths objectAtIndex:0]
destViewController.productName =[[_productList objectAtIndex:indexPath.row]valueForKey:#"url"];
[self.collectionView deselectItemAtIndexPath:indexPath animated:NO];
}
}
#end
ProductDetailViewController.h
`#import <UIKit/UIKit.h>
#interface ProductDetailViewController : UIViewController
- (IBAction)buyButton:(id)sender;
- (IBAction)closeButton:(id)sender;
#property (weak, nonatomic) IBOutlet UIImageView *productImage;
#property (weak, nonatomic) NSString *productName;
#end`
ProductDetailViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.productImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.productName]]];
//code to get productId
}
- (IBAction)buyButton:(id)sender {
//code to make server call with productId.
}
Server Response Format in JSON
{"rsBody":
[{"productId":11,
"productImageUrl":"http:xxxx"},
{"productId":9,
"productImageUrl":"http:"xxxx"}]}
For your first question, this line
self.productImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.productName]]];
is blocking the main thread. Meaning the app will go to the server download the entire image before updating the screen or allowing interactions, which is bad.
NSURL *url = [[NSURL alloc]initWithString:self.productName];
dispatch_queue_t imageFetchQ = dispatch_queue_create("image fetcher", NULL);
dispatch_async(imageFetchQ, ^{
NSData *imageData = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = [[UIImage alloc]initWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
self.productImage.image=image;
}
});
});
Try the block above instead. It will fetch the product image on a different thread.
Question two: Two transfer data between view controllers do what you're doing in prepareForSegue setup the public properties of the destination view controller.
Question three: Optimum way is to create an NSObject class that you read the data from the dictionary into properties on that class through some method called like setupFromDictionary.
Here you would have an Object called product with a productID property and productImageURL property. That way you're not constantly calling valueForKey or objectForKey on some dictionary.

Transfering code from cellForItemAtIndexPath to a CollectionViewCell (Parse Back-End)

I'm using Parse as the database for my app. I want to create a CollectionViewCell and transfer my code there, instead of having it inside the View Controller's cellForItemAtIndexPath. How do I do this?
Thanks.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"productCell";
ProductCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
PFObject *product = [self.products objectAtIndex:indexPath.row];
NSString *price = [NSString stringWithFormat:#"$%#.00", product[#"price"]];
cell.price.text = price;
PFFile *userImageFile = product[#"firstThumbnailFile"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *thumbnailImage = [UIImage imageWithData:imageData];
UIImageView *thumbnailImageView = [[UIImageView alloc] initWithImage:thumbnailImage];
cell.image.image = thumbnailImageView.image;
}
}];
return cell;
}
Cell.h
#interface ProductCell : UICollectionViewCell
#property (nonatomic, weak) IBOutlet UIImageView *image;
#property (nonatomic, weak) IBOutlet UILabel *price;
#end
Remember that cellForIndexPath is called over and over as cells scroll into view. So it's bad practice to make unguarded network requests in that method.
If you want to fetch the images lazily, add logic that caches the retrieved results, and only fetch images that haven't been fetched before...
// in private interface
#property(strong,nonatomic) NSMutableDictionary *imageForProduct;
// in init
self.imageForProduct = [#{} mutableCopy];
A method to fetch an image...
- (void)imageForProduct:(PFObject *)product completion:(void (^)(UIImage *))completion {
PFFile *userImageFile = product[#"firstThumbnailFile"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
UIImage *image;
if (!error) {
image = [UIImage imageWithData:imageData];
}
completion(image);
}];
}
Now, in cellForIndexPath, we can't count on the state of the collection being the same by the time the image arrives, so rather than retaining manipulating the cell in the completion block, just reload the index path...
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"productCell";
ProductCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
PFObject *product = [self.products objectAtIndex:indexPath.row];
NSString *price = [NSString stringWithFormat:#"$%#.00", product[#"price"]];
cell.price.text = price;
if (self.imageForProduct[product.objectId]) {
cell.image = self.imageForProduct[product.objectId];
} else {
cell.image = // optionally put a placeholder image here
[self imageForProduct:product completion:^(UIImage *)image {
self.imageForProduct[product.objectId] = image;
[collectionView reloadItemsAtIndexPaths:#[indexPath]];
}];
}
return cell;
}
create a method in your custom cell which is exposed in your .h file.
This method should receive an argument of type PFObject.
Then in you cellForItemAtIndexPath, call that method and pass your object in that method.
And in the implementation of that method, extract the details from your object and assign them to respective properties.

How to cache images in UITableView without external Libraries?

Iam trying to cache images without using external libraries in UITableview.
But i didnt get any results for that. My images are loading from URL .i have more than 40 images and is there any way to cache rather than loading directly ??
am using following code for loading image form URL
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"cell";
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[testingTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier]
;
}
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.img.image = [UIImage imageWithData:data];
});
});
return cell;
}
You can use NSCache, NSCache works like an NSMutableDictionary with the advantage that is thread safe, with also some auto removal policies
Depending on your requirements you can create a singleton instance of it:
#interface SharedCache : NSCache
+ (id)sharedInstance;
#end
#implementation SharedCache
- (void) emptyCache{
[self removeAllObjects];
}
-(void) dealloc{
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
-(id) init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(emptyCache) name:UIApplicationDidReceiveMemoryWarningNotification object:[UIApplication sharedApplication]];
}
return self;
}
+(id)sharedInstance
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
#end
Of course you should take care about check whether or not the image is already cached with a specified key.
Why wouldn't you use libraries? A very good one to use is UIImageView+AFNetworking from AFNetworking UIKit which loads an Image from a URL asynchronously and also caches your images.
example code:
[yourImageView setImageWithURL:youURL placeholderImage:[UIImage imageNamed:#"placeholder.png"]];

I can't get my array from JSON to load into the UITableView

The .h contains
#interface HomeTVC : UITableViewController
#property (nonatomic, strong) NSArray *spotTitle;
and the .m contains
#import "HomeTVC.h"
#interface HomeTVC ()
#end
#implementation HomeTVC
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
This is where I make the server request and get the data
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *homeDataURL = [NSURL URLWithString:#"XXXXX"];
NSData *jsonSpots = [NSData dataWithContentsOfURL:homeDataURL];
NSDictionary *spotTableDictionary = [NSJSONSerialization JSONObjectWithData:jsonSpots options:0 error:NULL];
NSArray *spotTitle = [spotTableDictionary valueForKey:#"title"];
NSLog(#"%#",spotTitle);
That NSLog prints the array I want to pass into the tableview in the terminal and everything here seems to work properly.
Here's where my problems start:
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.spotTitle count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [self.spotTitle objectAtIndex:indexPath.row];
return cell;
}
I've been fumbling around trying to connect the array that gets passed to that NSLog statement to my tableview and I'm not sure what I'm doing wrong at this point.
Both dataSource and delegate are connected to HomeTVC in the main storyboard.
The program compiles and runs with no errors or warnings and loads an empty tableview.
Maybe I'm missing something super basic (I'm really new to programming) and this is the first time I've tried to pass in an external db.
NSArray *spotTitle = [spotTableDictionary valueForKey:#"title"];
self.spotTitle = spotTitle; //Do you forget assign to your property?
NSLog(#"%#",self.spotTitl);
Why to create another variable when you can use your property.
Just do this::
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *homeDataURL = [NSURL URLWithString:#"XXXXX"];
NSData *jsonSpots = [NSData dataWithContentsOfURL:homeDataURL];
NSDictionary *spotTableDictionary = [NSJSONSerialization JSONObjectWithData:jsonSpots options:0 error:NULL];
self.spotTitle = [spotTableDictionary valueForKey:#"title"];
NSLog(#"%#",self.spotTitle);
That should solve your problem. Also do not use same name for property & local variables, it leads to unnecessary confusion as you are dealing with it.

Resources