Unable to store/retrieve files properly from NSDocumentsDirectory - ipad

One of the developer is implementing a phonegap project supporting cross platform(ios & android). Things are going weird whenever there ain't any plugin available for ios. I am exhausted with a requirement that has come up, we save pdf files generated in app to documents directory. In android, when choose file is clicked, a file explorer opens up for choosing file from desired location. I had to write a custom plugin for ios, as things are sandboxed in ios...only way a user can choose is files saved in app documents directory. I am trying to fetch the documents(pdf files) from the directory and populate them in table view. Actually I followed this link on Git repository for saving pdf file. The link follows a traditional way of saving in documents directory, but I don't see the file getting saved with extension '.pdf',surprisingly the pdf files are visible with extensions in temp directory embedded in unique folders. Moreover it wipes off the file from documents directory after the user opens the file in appropriate reader s/w.
When I tried to retrieve the files from temporary directory using the below code:
NSString *docPath = NSTemporaryDirectory();
self.filesArray = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:docPath error:NULL] mutableCopy];
for (NSString *file in _filesArray) {
NSString *actualFile = [NSString stringWithFormat:#"/%#",file];
docPath = [docPath stringByAppendingString:actualFile];
}
[_filePathsArray addObject:docPath];
As expected its returning only directories (I mean the folders).... and the pdf files are hidden in those subdirectories. I need to extract these files and show up in table view. Here is the sample code of the plugin I created:
- (NSMutableDictionary *)callbackIds {
if (_callbackIds == nil) {
_callbackIds = [[NSMutableDictionary alloc] init];
}
return _callbackIds;
}
-(void)open:(CDVInvokedUrlCommand *)command
{
[self.callbackIds setValue:command.callbackId forKey:#"open"];
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
self.listOfFiles = [[UITableView alloc] initWithFrame:CGRectMake(230, 210, width/1.8, height/1.8) style:UITableViewStylePlain];
self.listOfFiles.dataSource = self;
self.listOfFiles.delegate = self;
self.listOfFiles.scrollEnabled = YES;
self.listOfFiles.rowHeight = tableHeight;
[self.viewController.view addSubview:_listOfFiles];
}
#pragma mark - TableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
self.filePathsArray = [[NSMutableArray alloc]init];
self.filesArray = [[NSMutableArray alloc]init];
NSString *docPath = NSTemporaryDirectory();
self.filesArray = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:docPath error:NULL] mutableCopy];
for (NSString *file in _filesArray) {
NSString *actualFile = [NSString stringWithFormat:#"/%#",file];
docPath = [docPath stringByAppendingString:actualFile];
}
[_filePathsArray addObject:docPath];
return _filesArray.count;
}
#pragma mark - TableViewDelegate
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = [NSString stringWithFormat:#"S%1dR%1d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [_filesArray objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Send result back to the javascript plugin
NSString *resultingPath = [self.filePathsArray objectAtIndex:indexPath.row];
[self returnPluginResult:resultingPath toCallback:#"open" withError:NO];
[_listOfFiles removeFromSuperview];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #"Choose File";
}
#pragma mark - Plugin Callback
- (void)returnPluginResult:(NSString *)result toCallback:(NSString *)callback withError:(BOOL)error
{
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:result];
if (!error) {
[self writeJavascript:[pluginResult toSuccessCallbackString:[self.callbackIds valueForKey:callback]]];
}
else {
[self writeJavascript:[pluginResult toErrorCallbackString:[self.callbackIds valueForKey:callback]]];
}
}
Someone please guide me with a solution or subsequent helpful links. I tried every samples of code over humongous googling and nothing seemed to solve my problem.
Thanks everyone in advance :)

The link I followed for storing the pdf is actually removing the file from documents directory upon storage. Truncating the removal code solved the issue for me. Hope this helps someone, thanks :)

Related

Objective C read csv and populate in tableview

Hi guys I am new to Objective C. I want to make an app where it can read a csv file locally and display the data in a specific column in the tableview.
1)Read csv locally
2)Display csv data (let's say fifth column "ItemName") in the tableview
Thanks for any advice.
- (void)viewDidLoad {
[super viewDidLoad];
NSString *strPath = [[NSBundle mainBundle] pathForResource:#"issues" ofType:#"csv"];
NSString *strFile = [NSString stringWithContentsOfFile:strPath encoding:NSUTF8StringEncoding error:nil];
if (!strFile) {
NSLog(#"Error reading file.");
}
issues = [[NSArray alloc] init];
issues = [strFile componentsSeparatedByString:#","];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return[issues count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [issues objectAtIndex:indexPath.row];
return cell;
}
The way you do the parsing is only making columns of the whole file. First you need to separate by line-breaks (probably '\n'), then you can separate each line by ',' and each time take the 5th element and add it to an NSMutableArray (issues).
[strFile componentsSeparatedByString:#","] is not really CSV-parsing, there are more complex libraries available for that on cocoapods. If you need error-handling, etc. you better go with a library.

Access PDF files in my app IOS

Ultimate Goal: upload pdf to AWS S3 server
Where i am now:
I've been developing on IOS for over a month now and one thing it lacks is access to a simple file management system. Coming off of Android I could simply open a view which would let me access the downloads, photos, Google Drive, etc. On Android its simple, I choose the PDF I want to upload and that's it. On IOS I have yet to find a way to access PDF's or files. Only thing that works so far is viewing photos and videos and choosing one of them to upload.
is there a way to access a PDF on an IPad/IPhone to upload to an AWS S3 server?
My code so far:
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
NSArray *filePathsArray;
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
if ([filePathsArray count] > 0){
return [filePathsArray count];
}else{
return 1;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MainCell"];
}
cell.textLabel.text = [documentsDirectory stringByAppendingPathComponent:[filePathsArray objectAtIndex:indexPath.row]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *pdfPicked = cell.textLabel.text;
NSLog(#"PDF is: %#", pdfPicked);
}
#end
This code will look through the files in the documents folder and display the file path of each file in a UITableView. If i add a PDF to the documents folder then i can see it on the table view but apparently you cannot access the documents folder on an actual IPhone or IPad.
you can use document picker to pick documents from icloud and outside app's sandbox.
you can get reference of document picker here DocumentPicker
for document picker demo you can click on github

Updating uiprogress bar in cell rows

I am building an app that will allow users to download and read issues of a journal. I am using the Download Manager framework created by Robert Ryan and I modified the test project that came with the framework to have it work in my project (there are no issues with the framework). On each row in the table there is a Issue Cover Image (UIImageView), Download/Read label (UILabel), Issue Date label (UILabel), and a progress bar (UIProgressView) all are properties of a UITableViewCell. When a user taps the row, it initiates the download process of the issue which is reflected in the progress bar; after the download completes, the progress bar becomes hidden and the Download title of the label changes to Read, and when the user taps the row again to read the downloaded journal it opens a PDF viewer in a viewcontroller. I haven't added the Read functionality as yet. All this works fine except as a test I have 2 issues of the journal in the table each in a row with its ``. When I tap the first row, the progress bar reflects the download progress and it works fine. However, when I tap the second row, the download progress is reflected in the progress bar of the first row not the second row as expected (the progress bar remains static). It does download the second journal and everything works fine. It's just this unexpected behavior where the download progress of the second row is reflected in the progress bar in the first row. I still have to streamline the code and clean it up but the relevant code sections are below:
// optional method to indicate progress of individual download
//
// In this view controller, I'll update progress indicator for the download.
- (void)downloadManager:(DownloadManager *)downloadManager downloadDidReceiveData: (Download *)download;
{
for (NSInteger row = 0; row < [downloadManager.downloads count]; row++)
{
if (download == downloadManager.downloads[row])
{
[self updateProgressViewForIndexPath:[NSIndexPath indexPathForRow:row inSection:0] download:download];
break;
}
}
}
#pragma mark - Table View delegate and data source methods
// our table view will simply display a list of files being downloaded
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return[jitsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DownloadCell";
DownloadCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[DownloadCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
jits * jitsInstance = nil;
jitsInstance = [jitsArray objectAtIndex:indexPath.row];
cell.issue.text = jitsInstance.issue;
NSString * myCoverURL = [NSString stringWithFormat:#"%#", jitsInstance.coverimage];
UIImage* myImage = [UIImage imageWithData:
[NSData dataWithContentsOfURL:
[NSURL URLWithString: myCoverURL]]];
cell.coverimage.image = myImage;
[cell.progressView setProgress:0];
NSString * myURL = [NSString stringWithFormat:#"%#", jitsInstance.url];
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *downloadFolder = [documentsPath stringByAppendingPathComponent:#"downloads"];
NSString * fileName = [[NSString alloc]initWithFormat:#"%#", [myURL lastPathComponent]];
NSString* foofile = [downloadFolder stringByAppendingPathComponent:fileName];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
NSLog(#"Search file path: %#", foofile);
if (!fileExists) {
[cell.downloadButton setTitle:#"Download" forState:normal];
[cell.progressView setHidden:NO];
NSLog(#"File does not exist!");
}
else if (fileExists){
NSLog(#"File exist!");
[cell.downloadButton setTitle:#"Read" forState:normal];
[cell.progressView setHidden:YES];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *downloadFolder = [documentsPath stringByAppendingPathComponent:#"downloads"];
jits * jitsInstance = nil;
jitsInstance = [jitsArray objectAtIndex:indexPath.row];
NSString * myURL = [NSString stringWithFormat:#"%#", jitsInstance.url];
self.downloadManager = [[DownloadManager alloc] initWithDelegate:self];
self.downloadManager.maxConcurrentDownloads = 4;
NSString *downloadFilename = [downloadFolder stringByAppendingPathComponent:[myURL lastPathComponent]];
NSURL *url = [NSURL URLWithString:myURL];
[self.downloadManager addDownloadWithFilename:downloadFilename URL:url];
self.cancelButton.enabled = YES;
self.startDate = [NSDate date];
[self.downloadManager start];
}
#pragma mark - Table view utility methods
- (void)updateProgressViewForIndexPath:(NSIndexPath *)indexPath download:(Download *)download
{
DownloadCell *cell = (DownloadCell *)[self.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:indexPath.row inSection:0]];
// if the cell is not visible, we can return
if (!cell)
return;
if (download.expectedContentLength >= 0)
{
// if the server was able to tell us the length of the file, then update progress view appropriately
// to reflect what % of the file has been downloaded
cell.progressView.progress = (double) download.progressContentLength / (double) download.expectedContentLength;
}
else
{
// if the server was unable to tell us the length of the file, we'll change the progress view, but
// it will just spin around and around, not really telling us the progress of the complete download,
// but at least we get some progress update as bytes are downloaded.
//
// This progress view will just be what % of the current megabyte has been downloaded
cell.progressView.progress = (double) (download.progressContentLength % 1000000L) / 1000000.0;
}
}
I think your issue may lie in the following code:
for (NSInteger row = 0; row < [downloadManager.downloads count]; row++)
{
if (download == downloadManager.downloads[row])
{
[self updateProgressViewForIndexPath:[NSIndexPath indexPathForRow:row inSection:0] download:download];
break;
}
}
What this seems like it's essentially doing is finding the first cell in the downloads array, calling updateProgressViewForIndexPath on that first cell it finds, then stopping. There are a number of ways to fix this issue, but the first that comes to mind is once you tell yourself to update the cell at that index path when the if-statement evaluates to true, remove that item from the downloadManager's downloads array, so next time through it won't be there. Give that a try and let me know if that works..
Also, on a side note... I would think that you don't want to do the following two lines every time a row is selected:
self.downloadManager = [[DownloadManager alloc] initWithDelegate:self];
self.downloadManager.maxConcurrentDownloads = 4;
It would seem to me that is something you'd want to do perhaps in your init method of your tableView so it only occurs once, rather than every time the user taps a row. Perhaps you're attempting to create and set as a property a new download manager every time? That sort of seems unorthodox to me. If I had access to the project I think I might be better help debugging. Any chance you'd want to share the project if my response didn't help?

why am I getting NSRangeException in Xcode

I am trying to load a plist from my project, this was working until I accidentally deleted my plist. the plist has 5 arrays, with 2 elements apiece. I know that I the program is trying to access beyond the range of the array, but what I don't know is where this index is set? Here is the code that it bombs on: this code is executed twice successfully,then for some reason it tries to access it a third time and bombs on the first line,why?
It throws this exception:
NSRangeException -[_NSCFARRAY objectAtIndex] index(2) beyond bounds (2)
please help, this is for a final project due on Monday and now I feel like I have to start over again.
NSString *nameOfAccount = [account objectAtIndex:indexPath.row];
cell.textLabel.text = nameOfAccount;
NSString *accountNumber = [number objectAtIndex:indexPath.row];
cell.detailTextLabel.text = accountNumber;
Since you are displaying the data in same cell, you can include both name and number of account into a dictionary or a custom model object which will hold both info.
In your plist this might be the structure, array of dictionary objects
When you are displaying the info. For the dataSource create an array say accounts.
#define kAccountName #"Name"
#define kAccountNumber #"Number"
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filePath = [[NSBundle mainBundle]pathForResource:#"Accounts" ofType:#"plist"];
self.accounts = [NSArray arrayWithContentsOfFile:filePath];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.accounts count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *account = self.accounts[indexPath.row];
cell.textLabel.text = account[kAccountName];
cell.detailTextLabel.text = account[kAccountNumber];
// Configure the cell...
return cell;
}
Source code

Error reading plist file for fill a table

I'm developing an app for iPhone but I've a problem...
I've a view with some textField and the informations writed in them are saved in a plist file. With #class and #import declarations I import this view controller in another controller that manage a table view.
The code I've just wrote appear to be right but my table is filled up with 3 same row...
I don't know why the row are 3...
Can anyone help me?
This is the code for add info:
#implementation AddWishController
#synthesize titleField, linkField, descField;
-(NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:plistPath];
}
-(IBAction)done {
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:titleField.text];
[array addObject:linkField.text];
[array addObject:descField.text];
[array writeToFile:[self dataFilePath] atomically:YES];
[array release];
[self dismissModalViewControllerAnimated:YES];
}
And this control the table:
#import "WishlistController.h"
#import "AddWishController.h"
#implementation WishlistController
#synthesize lista;
-(IBAction)newWish {
AddWishController *add = [[AddWishController alloc] initWithNibName:#"AddWish" bundle:nil];
[self.navigationController presentModalViewController:add animated:YES];
[add release];
}
-(NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:plistPath];
}
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *data = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];
return [data count];
[data release];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
cell.textLabel.text = [array objectAtIndex:0];
cell.detailTextLabel.text = [array objectAtIndex:2];
NSLog(#"%#", array);
}
return cell;
}
Your first problem is that NSArray writeToFile: doesn't append to an existing file. It just writes the complete contents of the array to the file. If a file by the same name already exist, then the function overwrites it.
This means that in your code at present, you only ever save an array with three elements. No matter how many times the user saves in the AddWishController's view, only the last three pieces of information captured are ever preserved on disk.
Secondly, your WishlistController is misconfigured.
This:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *data = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];
return [data count];
[data release];
}
Will always return a count of three because the array in the file always has three elements. However, even that is wrong because you don't want to display each element in separate cell. Your cellForRowAtIndexPath: very clearly puts the first and last elements of the array into each and every cell.
At the very least here, you need a two-dimensional array. Better yet you need an array of dictionaries. Each dictionary will hold the results of one "done" operation in -[AddWishController done]. Put add each dictionary to an array. Then in your tableview controller, return the count of the array for the number of rows in the table. Then in cellForRowAtIndexPath: you should get the dictionary in array element of indexpath.row. Then get the text for the cell UI elements from each entry in the dictionary.
Usually, you also would not save to file until the app quits. Instead, put the array in an property of the app delegate. In AddWishController create a property to refers to the app delegates property. Do the same in the tableview controller. Now you can populate the array in the first controller and read it from the second.
Basically, you need to start over from scratch.
In WishController# load, you put three different items into the Array, So of course, if in WishlistController# tableView: numberOfRowsInSection: you return [data count] as the number of rows, you get three rows.
On the other Hand, you in WishlistController# tableView: cellForRowAtIndexPath: you do not look, which entry should be presented, so it will always show only the one and only cell.
If you want to present only one cell in your table, you replace your WishlistController# tableView: numberOfRowsInSection: with
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
If you want to show multiple Wishes, you better make a real object of it, or at least use NSDictionary, where one entry in the Dictionary represents one object (=Wish) with multiple attributes (title, link, desc).
If for your first steps in Cocoa/Objective-C you really really want not to look into NSDictionary yet, you could also
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return floor([data count]/3);
}
and then in #tableView: cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
int row = indexPath.row * 3;
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
cell.textLabel.text = [array objectAtIndex:row];
cell.detailTextLabel.text = [array objectAtIndex:row+2];
NSLog(#"%#", array);
}
return cell;
}
But this definitly is only for prototyping-to-get-something-displayed. You soon want to look into NSDictionary and before releasing anything, you better learn the use of proper objects for your Data Model, for instance with Core Data. Really.
two more things:
-In WishlistController#tableView:numberOfRowsInSection: the line
[data release];
after the return never gets called. You probably want to
[data autorelease];
before the return-statement.
- You do not want to read a file // look for your objects each time a row in your table gets displayed. Create an array as an instance-variable of your controller and use it as your datasource.

Resources