Cannot add UIDocument into an array - objective-c

If I try to add an opened UIDocument into an array I get nothing out. This might be how it is supposed to work, I'm not sure.
- (void)loadDocAtURL:(NSURL *)fileURL withClassName:(NSString *)className {
id doc = [[NSClassFromString(className) alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
if (!success) {
NSLog(#"Failed to open %#", fileURL);
return;
}
NSLog(#"I'm a doc. My class is %#, my title is %#", NSStringFromClass([doc class]), [doc title]);
dispatch_async(dispatch_get_main_queue(), ^{
//[self addOrUpdateEntryWithURL:fileURL metadata:metadata state:state version:version];
[_tableList addObject:doc];
[self.tableView reloadData];
NSLog(#"%d", _tableList.count);
});
}];
};
That NSLog returns: I'm a doc. My class is Song, my title is A New Song
So far so good.
[self.tableView reloadData], reloads the table correctly and the correct number of cells are displayed, only they are empty, this is why:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Song *theSong = [tableList objectAtIndex:indexPath.row];
NSLog(#"I am a %#", NSStringFromClass([theSong class]));
UILabel *titleLabel = (UILabel *)[cell viewWithTag:0];
UILabel *lyricLabel = (UILabel *)[cell viewWithTag:1];
NSLog(#"I'm in the table view. My title is %#", [theSong lyric]);
titleLabel.text = theSong.title;
lyricLabel.text = theSong.lyric;
[theSong closeWithCompletionHandler:^(BOOL success) {
// Check status
if (!success) {
NSLog(#"Failed to close %#", theSong.fileURL);
// Continue anyway...
}
}];
return cell;
}
Those two NSLogs output: I am a (null) and I'm in the table view. My title is (null)
When I breakpoint and look at theSong after its grabbed, it is completely empty.
This is leading me to think that you cannot open a UIDocument, stick it in an array and pull it back out of the array. Am I correct?

If the song is nil, then almost certainly the array is nil. I notice you refer to it both as _tableList and as tableList. My guess is those are not the same pointer.
Try using _tableList in cellForRowAtIndexPath. Log it to confirm that it's non-nil.
You can disprove your theory about the array by logging [_tableList lastObject] right after you add it.

Related

Accessory checkmarks disappear when scrolling Objective-C

I have a tableview that I can add and remove multiple checkmarks. The only issue is if I put 3 checkmarks and scroll away, when I return the checkmarks are gone. I can't find anywhere on the internet a solution that works, and I've tried several variation and still nothing.
This is my code in cellForRowAtIndex that should be holding the checkmarks in place.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseIdentifier = #"contactCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
NSDictionary *contact = [self.tableData objectAtIndex:indexPath.row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:1];
NSString *firstName = contact[#"firstName"];
nameLabel.text = [firstName stringByAppendingString:[NSString stringWithFormat:#" %#", contact[#"lastName"]]];
UILabel *phoneNumber = (UILabel *)[cell viewWithTag:2];
NSArray *phones = contact[#"phones"];
if ([phones count] > 0) {
NSDictionary *phoneItem = phones[0];
phoneNumber.text = phoneItem[#"value"];
}
UIImageView *cellIconView = (UIImageView *)[cell.contentView viewWithTag:888];
UIImage *image = contact[#"image"];
cellIconView.image = (image != nil) ? image : [UIImage imageNamed:#"smiley-face"];
cellIconView.contentScaleFactor = UIViewContentModeScaleAspectFill;
cellIconView.layer.cornerRadius = CGRectGetHeight(cellIconView.frame) / 2;
// Need to fix
if([checkedIndexPath isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Here is the didSelectRowAtIndexPath method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell* checkCell = [tableView cellForRowAtIndexPath:indexPath];
if(checkCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
checkCell.accessoryType = UITableViewCellAccessoryNone;
NSMutableArray *i = [[NSMutableArray alloc] init];
for (NSIndexPath *indexPath in [self.tableView indexPathsForSelectedRows]) {
[i addObject:self.tableData[indexPath.row]];
// Go inside pull the numbers from the users and save in an NSArray
// NSArray *contacts = i;
// self.recipients = [[NSMutableArray alloc] init];
for (NSDictionary* dict in i) {
// Grab phones
NSDictionary *contactNumber = [dict objectForKey:#"phones"];
for (NSDictionary* dict2 in contactNumber) {
// Grabs the phone numbers
NSString* value = [dict2 objectForKey:#"value"];
int index = [self.recipients indexOfObject:value];
[self.recipients removeObjectAtIndex:index];
[self.selectedUsers removeObjectAtIndex:index];
NSLog(#"The number that has a checkmark%#", value);
NSLog(#"the array of all%#", self.recipients);
NSLog(#"At index %lu", (unsigned long)[self.recipients indexOfObject:value]);
// [_recipients addObject:value];
}
}
// NSLog(#"Phone Numbers: %#",_recipients);
}
}
else
{
[self getNumber];
NSLog(#"clicking %#", self.recipients);
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
checkedIndexPath = indexPath;
}
}
I found The Solution:
You must save each indexPath into an array(put this code in didSelectRowAtIndexPath) and then in cellForRowAtIndexPath add the following code
if([self.checkedCells containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Also in the didSelectRowAtIndexPath
Make sure to delete the indexPath when deselecting the row.
if(checkCell.accessoryType == UITableViewCellAccessoryCheckmark) {
checkCell.accessoryType = UITableViewCellAccessoryNone;
[self.checkedCells removeObject:indexPath];
I hope this helps someone. I been wrestling with this all day.
Make checkedIndexPath a #property (nonatomic, strong) and use self.checkedIndexPath whenever you refer to it. You're losing the reference after didSelectRowAtIndexPath exits. Set a breakpoint in cellForRowAtIndexPath and look at checkedIndexPath, I bet it's nil.
Maybe you should check if the isEqual functionality does what you expect. You could make sure by trying:
if (_checkedIndexPath.section == indexPath.section &&
_checkedIndexPath.row == indexPath.row)
If you still do not get the expected result, perhaps log the values of section and row to see where it goes wrong.
Please note that if for some reason _checkedIndexPath is a weak variable or gets deallocated, this check will fail.
You could also check that your cells are properly dequeued before being modified and that you are returning the correct cells.
If you want to store more than one checked row, of course, you will need more than one indexPath variable (just one _checkedIndexPath will not do it).

Why are my UITableViewCell images only being loaded when I leave then return to a controller and not during viewDidLoad?

Having a slight problem with my UITableViewCell images. I'm loading my data straight from parse.com. My objects array that returns PFObject's is stored inside an NSMutable array named "people".
This is how I display the data in my table:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
Person *current;
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
current = [searchResults objectAtIndex:indexPath.row];
} else {
current = [people objectAtIndex:[indexPath row]];
}
[[cell textLabel] setText: [current valueForKey:#"name"]];
PFFile *userImageFile = [current valueForKey:#"image"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
UIImage *image = [UIImage imageWithData:imageData];
[[cell imageView] setImage: image];
}];
// [[cell imageView] setImage: [current image]];
[[cell detailTextLabel] setText: [current valueForKey:#"notes"]];
return cell;
}
The problem is when I load the app up and this view which is my main loads it doesn't load any images. However when I tap on a row just before the next controller is popped on screen I see the image for that row load and then when I tap the back button and go back to the main view again the rest of the tableViews images load.
Is this something to do with the images not being thumbnail versions?
I've tried wrapping the code in dispatch_async(dispatch_get_main_queue(), ^ { )}; with no luck. Can someone help me solve this issue?
Kind regards
Update to show where I call reload data:
-(void)viewDidAppear:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
[[self tableView] reloadData];
});
}
- (void)viewDidLoad
{
[super viewDidLoad];
people = [[NSMutableArray alloc] init];
PFQuery *query = [PFQuery queryWithClassName:#"People"];
[query whereKey:#"active" equalTo:#1];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
people = objects.mutableCopy;
dispatch_async(dispatch_get_main_queue(), ^ {
[[self tableView] reloadData];
});
I don't think there is anything wrong with your loading in your viewDidLoad.
My suspicion is that the UIImageView's frame is actually zero as you did not have a placeholder image while loading the actual images. The cell will not be redrawn again until the next time layoutSubviews is called again, even if your fetched image has loaded. So either set a placeholder image, or call:
[cell setNeedsLayout];
once your image is fully loaded.
Another alternative is to use PFImageView, a subclass of UIImageView, which takes care of everything for you.
PFFile *userImageFile = [current valueForKey:#"image"];
[cell imageView].image = [UIImage imageNamed:#"placeholder.jpg"]; // placeholder image
[cell imageView].file = userImageFile;
[[cell imageView] loadInBackground];
Instead of loading my data directly from parse.com into my tableView I loaded it into an object first. So each object was no longer an PFObject and now a Person object and I stored these in a mutable array which I accessed in my tableView.
Try it:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear]; //this is necessary for most time
//viewDidAppear be called in main thread, so just call reloadData directly
[self.tableView reloadData];
}
As mentioned in Apple document about - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath:
You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.
If you registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method.
For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.
So, do you forget to use the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling cellForRowAtIndexPath method?
Here is a discussion about this.
How I am doing this
In my UIViewController.m
#property (nonatomic, strong) NSMutableDictionary *imageDownloadsInProgress;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.imageDownloadsInProgress = [NSMutableDictionary dictionary];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
SRKProduct *productRecord = [stockArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (!productRecord.image || [productRecord.image isEqualToData:NULL] || productRecord.image.length == 0) {
if (_itemTableView.dragging == NO && _itemTableView.decelerating == NO)
{
[self startIconDownload:productRecord forIndexPath:indexPath];
}
cell.imageView.image = [[UIImage imageNamed:#"Placeholder.png"] makeThumbnailOfSize:CGSizeMake(50,50)];//This is just a placeholder and will be removed when original image is downloaded.
}
return cell;
}
#pragma mark -
- (void)startIconDownload:(SRKProduct *)srkproduct forIndexPath:(NSIndexPath *)indexPath
{
SRKIconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[SRKIconDownloader alloc] init];
iconDownloader.srkproduct = srkproduct;
[iconDownloader setCompletionHandler:^{
UITableViewCell *cell = [_itemTableView cellForRowAtIndexPath:indexPath];
// Display the newly loaded image
cell.imageView.image = [UIImage imageWithData:srkproduct.image];
NSLog(#"Image %d",[productAdapter updateproductImage:srkproduct]);
// Remove the IconDownloader from the in progress list.
// This will result in it being deallocated.
[self.imageDownloadsInProgress removeObjectForKey:indexPath];
}];
[self.imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
}
}
Then in SRKIconDownloader.h
#interface SRKIconDownloader : NSObject
#property (nonatomic, strong) SRKProduct *srkproduct;
#property (nonatomic, copy) void (^completionHandler)(void);
And in SRKIconDownloader.m
#implementation SRKIconDownloader
#pragma mark
- (void)startDownload
{
PFQuery *queryCouple = [PFQuery queryWithClassName:#"Product"];
[queryCouple whereKey:#"Name" equalTo:_srkproduct.productName];
[queryCouple findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if ([objects count] > 0) {
for (PFObject *object in objects) {
PFFile *image = (PFFile *)[object objectForKey:#"Image"];
[image getDataInBackgroundWithBlock:^(NSData *data, NSError *error){
_srkproduct.image = data;
// call our delegate and tell it that our icon is ready for display
if (self.completionHandler)
self.completionHandler();
}];
break;
}
}
else{
}
}
}];
}
#end

I'm trying to implement infinite scrolling into my UITableViewController and unsure how to use the database results returned

Currently trying to implement infinite scrolling into my app using this plugin: https://github.com/pronebird/UIScrollView-InfiniteScroll
So far I've added this code to my tableview controller viewDidAppear and viewDidDisappear methods:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// setup infinite scroll
// keep a weak reference to table view
__weak UITableView *weakTableView = self.tableView;
[self.tableView addInfiniteScrollWithHandler:^{
// keep a strong reference to table view
__strong UITableView *strongTableView = weakTableView;
// seems like our table view didn't make it
if(strongTableView == nil) return;
//
// fetch your data here, can be async operation,
// just make sure to call finishInfiniteScroll in the end
// finish infinite scroll animation
[strongTableView finishInfiniteScroll];
}];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// remove infinite scroll
[self.tableView removeInfiniteScroll];
[[self tableView] reloadData];
}
I drag the table and the spinner shows underneath the last row and disappears after a second or two. Now all I need to do is get the data from my array and add it to block in the viewDidAppear code.
This is how I currently get my parse.com data into an NSMuteableArray instance named "people":
- (void)populatePeopleArrayWithCloudData {
// Grab data for datasource and store in people array
NSLog(#"view did load");
people = [[NSMutableArray alloc] init];
PFQuery *query = [PFQuery queryWithClassName:#"People"];
[query whereKey:#"active" equalTo:#1];
[query orderByDescending:#"createdAt"];
[query setLimit:10];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
for (PFObject *object in objects) {
Person *person = [[Person alloc] init];
[person setName:[object objectForKey:#"name"]];
[person setNotes:[object objectForKey:#"notes"]];
[person setAge:[[object objectForKey:#"age"] intValue]];
[person setSince:[object objectForKey:#"since"]];
[person setFrom:[object objectForKey:#"from"]];
[person setReferenceNumber:[object objectForKey:#"referenceNumber"]];
PFFile *userImageFile = object[#"image"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
[person setImage:image];
}
}];
[person setActive:[[object objectForKey:#"active"] intValue]];
[person setObjectId:[object objectId]];
[people addObject:person];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
NSLog(#"Calling reloadData on %# in viewDidLoad", self.tableView);
[self.tableView reloadData];
}];
}
I limit results to 10. Now what I wish to do is keep grabbing the next 10 results that haven't already been grabbed every time I scroll to the bottom of the table. This code that helps me do this needs to go in the block mentioned above.
The "people" instance is used by my tableviewdatasource methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
Person *current;
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
current = [searchResults objectAtIndex:indexPath.row];
} else {
current = [people objectAtIndex:[indexPath row]];
}
[[cell textLabel] setText: [current name]];
[[cell imageView] setImage: [current image]];
[[cell detailTextLabel] setText: [current notes]];
return cell;
}
How do I use my database results with this plugin? As you can see I limit results to 10 and I need to grab the next 10 when I've scrolled to the bottom of the table and add them after the last row in the table.
Kind regards
UPDATE - my numbers of rows in section method as it stands:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
return [searchResults count];
} else {
return [people count];
}
}
Happy to help, but you should probably give it a shot first for us to provide feedback. A few thoughts to get you going...
The general idea is to use the "skip" property on PFQuery to get the next 10. Each time you call it, you add 10.
So create your query as you do, keep it around in a property, but move your findObjectsInBackgroundWithBlock call to your infiniteScrollHandler, adding 10 to skip each time after you call it. Then at the end of the handling (where you call table reload now), call [strongTableView finishInfiniteScroll]
In your numberOfRows, you'll have to provide the maximum number of people available at your source.

Dispatch Queue and global NSMutableDictionary - Objective C

I'm trying to use a global NSMutableDictionary from a dispatch queue. However, the items keep coming back NULL.
What I'm trying to do is access an external json file with a dispatch_queue, then populate a UITableView with this info.
Here's what I have
vc.h:
#interface viewcontroller {
NSMutableDictionary *jsonArray;
}
vc.m:
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) //1
#define jsonTest [NSURL URLWithString:#"http://www.sometest.com/test.php"]
-(void)viewDidLoad {
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
jsonTest];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
// if I run the log here, I can access jsonArry and the log prints correctly
NSLog(#"City: %#", [jsonArray objectForKey:#"city"];
});
}
-(NSMutableDictionary *)fetchedData:(NSData *)responseData {
NSError *error;
jsonArray = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
return jsonArray;
}
/********************* Table formatting area **********************/
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.ipTable) {
if ([ipArray count] == 0){
return 1;
} else { // meta table
return [ipArray count];
}
} else { // IP Meta Data
return [jsonArray count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.myTable) {
NSString *CellIdentifier = NULL;
if ([ipArray count] == 0) {
CellIdentifier = #"No Cells";
} else {
CellIdentifier = #"IP Cell";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if ([ipArray count] == 0)
{
[cell.textLabel setText:NSLocalizedString(#"None Found", nil)];
return cell;
} else {
IPAddr *theip = [ipArray objectAtIndex: [indexPath row]];
NSString *theipname = [theip ipName];
if ([theipname isEqualToString:#""]) {
[cell.textLabel setText: [theip ipNum]];
[cell.detailTextLabel setText:NSLocalizedString(#"noName", nil)];
} else {
[cell.textLabel setText: [theip ipName]];
[cell.detailTextLabel setText: [theip ipNum]];
}
return cell;
}
} else { // meta table
static NSString *CellIdentifier = #"metaCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// jsonArray content would go here to fill the cells.
/******************** something here to fill the cells using jsonArray ********************/
return cell;
}
} // END UITAbleViewCell
If I access the jsonArray inside the queue, it returns fine and prints the log for the city.
However, if I try to use it outside the queue, it returns NULL.
I'm trying to figure out what is happening, any ideas?
I need to use jsonArray in different methods in the same view, so I need it to be global.
I am fairly sure that the problem is that the data source methods (numberOfRowsInSection,
cellForRowAtIndexPath) are called before the background thread has finished and
filled the jsonArray. Therefore you have to reload the table view when the background
thread has finished:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(kBgQueue, ^{
NSData *data = [NSData dataWithContentsOfURL:jsonTest];
NSError *error;
NSArray *tmpArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
dispatch_sync(dispatch_get_main_queue(), ^{
// Assign new data to data source and reload the table view:
jsonArray = tmpArray;
[self.metaTableView reloadData];
});
});
}
So the table view would be empty initially, and reloaded later when the data has
arrived.
Try to call the other method(which is using your jsonarray) through nsnotification...I am not sure there might some other ideas/ways of doing this.But i am presenting what i have in my mind.
Put this code inside your fetchedData method,
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(someMethod:) name:#"JSonDownloaded" object: jsonArray];
[[NSNotificationCenter defaultCenter] postNotificationName:#"JSonDownloaded" object: jsonArray];
-(void)someMethod:(NSNotification *)nspk
{
NSLog(#"%#",nspk.object);
//Only after this you can able to access the jsonArray.
}
Don't forget to unregister the observer.
jsonArray is just an instance variable, but not a property. Thus, assigning an object to it does not retain it, and the object may be released as soon as the program returns to the run loop.
I suggest replacing the iVar by #property (strong) NSMutableDictionary *jsonArray; and #synthesize jsonArray;, and assigning the object to it by self.jsonArray = ...
EDIT (see comment of Martin R below):
Thus, if you are not using ARC, assigning an object to it does not retain it, and the object may be released as soon as the program returns to the run loop.
In this case, I suggest replacing the iVar by #property (retain) NSMutableDictionary *jsonArray; and #synthesize jsonArray;, and assigning the object to it by self.jsonArray = ...

Asynchronous loading image inside uitableviewcell

Hello I am trying to use EGOImageView inside a CustomTableViewCell who i made to customize the cell. This is the code where I used the EGOImageView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString* simpleTableIdentifier = #"Albums";
CustomTableCell* cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (!cell)
{
cell = [[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
NSLog(#"Show once or more times");
}
NSDictionary* dictionary = (NSDictionary*)[self.albumCollection objectAtIndex:indexPath.row];
cell.label.text = [dictionary valueForKey:#"name"];
EGOImageView* imageView = [[EGOImageView alloc] initWithPlaceholderImage:[UIImage imageWithContentsOfFile:#""]];
[imageView setImageURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=small&access_token=%#", (NSString*)[dictionary valueForKey:#"id"], [[FBSession activeSession] accessToken]]]];
[imageView setFrame:CGRectMake(0.0f,0.0f,78.0f,78.0f )];
[cell.iView addSubview:imageView];
[imageView release];
The image on each cell loading the same image. Would it be because it reused the cell while loading the image.
I found a problem I can't think of why the problem happened. I used the graph api to grab the image https://graph.facebook.com/%#/picture?type=small&access_token=%# where the first parameter was the album id.
To make myself easy to see the problem I only used one album on the cell, no matter what album i used the same photo turned up. But when I copy the link to the browser, the actual photo url shown on the address bar with the image shown and it shown the correct photos.
Does anyone know what was wrong.
Here is example. It loads user pics from some server in background and updates cell image. Note that imageView.image is set to nil at the beginning. This is dome for the case of cell reuse so that you will have no image rather than wrong image for the time while its downloading.
One more thing to add is that, would be also good to have a cache so that it does not download images all the time. Another nice thing is to not download images in edge networks.
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TransactionCell";
NSMutableArray *data = searching ? searchResult : dataSource;
NSDictionary *object = [data objectAtIndex:[indexPath row]];
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithIdentifier:CellIdentifier] autorelease];
}
cell.imageView.image = nil;
cell.textLabel.text = #"Your cell text";
NSString *contact = #"foo#gmail.com";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [appDelegate addUserPic:contact];
if (imgData == nil && netStatus == ReachableViaWiFi) {
NSString *url = [NSString stringWithFormat:#"http://somehost.com/userpic/%#", contact];
imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
}
dispatch_async(dispatch_get_main_queue(), ^{
UITableViewCell *updateCell = [self.tableView cellForRowAtIndexPath:indexPath];
if (updateCell) {
if (imgData) {
[appDelegate setUserPic:contact imgData:imgData];
updateCell.imageView.image = [UIImage imageWithData:imgData];
} else {
updateCell.imageView.image = nil;
}
/* This forces the cell to show image as now
it has normal bounds */
[updateCell setNeedsLayout];
}
});
});
return cell;
}