iphone - SetNeedsDisplay not working - iphone

I'm trying to refresh my main view in this code. It shows the right sub-view, but it's keeping the other views already shown. I already tried setNeedsDisplay and setNeedsLayout but no success.
Any ideas?
Code:
-(void)setViewsForLecture:(NSString *)date{
int scrollHeight = 0;
[self.view setNeedsDisplay];
FMDatabase* db = [DatabaseManager openDatabase];
NSString *query = [NSString stringWithFormat:#"select * from tbl_lectures where day like \"%%%#%%\" ", date];
FMResultSet *rs= [db executeQuery:query];
//Counts how many lectures
int position = 0;
while ([rs next]) {
NSMutableArray *speakers = [[NSMutableArray alloc] initWithCapacity:30];
NSString *lectureName = [rs stringForColumn:#"lecturename"];
FMResultSet *speakersList = [db executeQuery:#SELECT_SPEAKER_FOR_LECTURE, lectureName];
while ([speakersList next]) {
[speakers addObject:[speakersList stringForColumn:#"speaker"] ];
}
if ([speakers count] % 2 == 0)
{
scrollHeight += [speakers count]*40;
}
else
{
scrollHeight += (1 + ([speakers count] -1)/2)*40;
}
NSLog(#"Csantos: speakers for %#: %i",lectureName, [speakers count]);
UIView *aLecture = [CustomInterface viewForLecture:[rs stringForColumn:#"lecturename"]
onPosition:position
withSpeakers:speakers];
[self.scroll addSubview:aLecture];
[aLecture release];
[speakers release];
scrollHeight += 280;
position++;
}
self.scroll.contentSize = CGSizeMake(300, scrollHeight);
[db release];
}
Regards!

Try calling
[self.view setNeedsDisplay];
at the end of the method, after you've made the changes.

I got it working!
I think I didn't understand exactly how setNeedsDisplay works. In this case, was it supposed to redraw my ScrollView too?
Anyway, here is the code that works now:
-(IBAction)clickOnDate1{
for (UIView *view in [self.scroll subviews]) {
[view removeFromSuperview];
}
NSLog(#"Date1 clicked");
[self setViewsForLecture:#"4"];
}
and thanks PengOne for trying to help!

Related

Getting the Recepients list in MFMailComposeViewController

I am using MFMailcomposerViewController in my App. Everything is working fine, except that I am in need to Have the no. of recipients and the list of recipients the user is sending to.
Any help or solution regarding this issue..
I dont there is a standard way to do this, the delegate method mailComposeController:didFinishWithResult:error: gives you a reference to the composer view controller after it has been dismissed, but there are no accessors on MFMailComposeViewController which you could use to get the recipient count
A workaround would be to examine the subviews of the view controller, find the text field which was used to hold the recipients and get the text: see here
Finally I got the Answer and wanted to share it... I took a great help from [blog]: http://jomnius.blogspot.com/2011/02/how-to-find-mfmailcomposeviewcontroller.html
for (int x=0; x<[emailArray count]-1; x++) {
NSLog(#"%d). %#",x+1,[emailArray objectAtIndex:x]);
NSString *element = [emailArray objectAtIndex:x];
NSArray *arr = [element componentsSeparatedByString:#" & "];
if ([arr count]==1) {
++emailCount;
}
else{
int more = [[[arr objectAtIndex:1] substringToIndex:1] intValue];
emailCount+=(more+1);
}
}
- (NSString *)findEmailAddresses:(UIView *)view depth:(NSInteger)count
{
NSString *eAddress = nil;
if (!view)
return eAddress;
NSMutableString *tabString = [NSMutableString stringWithCapacity:count];
for (int i = 0; i < count; i++)
[tabString appendString:#"-- "];
NSLog(#"%#%#", tabString, view);
if ([view isKindOfClass:[UITextField class]])
{
// MAGIC: debugger shows email address(es) in first textField
// but only if it's about max 35 characters
if (((UITextField *)view).text)
{
eAddress = [NSString stringWithString:((UITextField *)view).text];
NSLog(#"FOUND UITextField: %#", eAddress ? eAddress : #"");
[emailArray addObject:eAddress];
}
}
NSArray *subviews = [view subviews];
if (subviews) {
for (UIView *view in subviews)
{
NSString *s = [self findEmailAddresses:view depth:count+1];
if (s) eAddress = s;
}
}
return eAddress;
}
There is no way to do this as of iOS 6 as mail composition is now done through an XPC service call to a remote process (MailCompositionService). There is a great explanation here: http://oleb.net/blog/2012/10/remote-view-controllers-in-ios-6/. The lowest level in the view hierarchy is now an _UIRemoteView which interfaces to the remote process. The code from the blog post at http://jomnius.blogspot.com/2011/02/how-to-find-mfmailcomposeviewcontroller.html will now alway return nil.

Objects added as subview to scrollview are not showing up

I am trying to add elements to a scroll view using this code:
int missionCount;
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *missionsDict = [responseString JSONValue];
/*NSArray *luckyNumbers = [json objectWithString:responseString error:&error];*/
NSLog(#"user Info array is: %#", missionsDict);
// NSDictionary *array = [luckyNumbers1 objectForKey:#"data"];
NSDictionary *missionsData;
missionsData = [missionsDict objectForKey:#"data"];
NSLog(#"missionsData is: %#", missionsData);
NSEnumerator *inner = [missionsData objectEnumerator];
missionsScroll.contentSize = CGSizeMake(768, 1005);
id value;
int badgeY1;
int badgeY2;
int badgeY3;
badgeY1 = 146;
badgeY2 = 188;
badgeY3 = 188;
while((value = [inner nextObject])) {
NSLog(#"value is: %#", value);
NSLog(#"progress is: %#", [value objectForKey:#"progress"]);
NSLog(#"user Info array is: %#", missionsDict);
NSLog(#"name is: %#",[value objectForKey:#"reward_definitions"]);
NSLog(#"missionsData is: %#", missionsData);
NSDictionary *moreData;
moreData = [value objectForKey:#"reward_definitions"];
NSEnumerator *inner2 = [moreData objectEnumerator];
id value2;
int badgeX;
int badgeCount;
badgeX = 0;
badgeCount = 0;
while((value2 = [inner2 nextObject])) {
UIProgressView *progressView;
progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(323, badgeY1, 372, 9)];
float progressValue;
progressValue = ([[[value objectForKey:#"progress"] objectForKey:#"earned"] floatValue] / [[[value objectForKey:#"progress"] objectForKey:#"possible"] floatValue]);
NSLog(#"progressValue is: %f", progressValue);
[progressView setProgress:progressValue];
[missionsScroll addSubview:progressView];
UILabel *missionName;
missionName = [[UILabel alloc] initWithFrame:CGRectMake(66, badgeY1, 227, 21)];
missionName.backgroundColor = [UIColor clearColor];
missionName.textColor = [UIColor whiteColor];
missionName.font = [UIFont fontWithName:#"Heiti TC" size:23.0];
missionName.text = [value objectForKey:#"name"];
[missionsScroll addSubview:missionName];
UILabel *requirementsLabel;
requirementsLabel = [[UILabel alloc] initWithFrame:CGRectMake(66, badgeY2+25, 227, 21)];
requirementsLabel.backgroundColor = [UIColor clearColor];
requirementsLabel.textColor = [UIColor whiteColor];
requirementsLabel.font = [UIFont fontWithName:#"Papyrus" size:19];
requirementsLabel.text = #"To complete you need:";
[missionsScroll addSubview:requirementsLabel];
NSLog(#"Image URL is: %#", [value2 objectForKey:#"image_url"]);
NSURL *url1 = [NSURL URLWithString: [NSString stringWithFormat:#"%#", [value2 objectForKey:#"image_url"]]];
NSData *urlData1 = [NSData dataWithContentsOfURL:url1];
UIImage *image1 = [UIImage imageWithData:urlData1];
UIImageView *badge = [[UIImageView alloc] initWithImage:image1];
[badge setFrame:CGRectMake(badgeX, badgeY2+70, 70, 70)];
[missionsScroll addSubview:badge];
[badge release];
badgeCount = badgeCount+1;
NSLog(#"badgeCount is: %i", badgeCount);
if (badgeCount == 4) {
NSLog(#"Badge Count = 4");
badgeY2 = badgeY2 +70;
badgeX = 0;
badgeCount = 0;
} else {
NSLog(#"Badge Count ≠ 4");
badgeX = badgeX +75;
}
}
NSLog(#"1st While loop done");
// NSLog(#"reward_definitions is: %#", [missionsData objectForKey:#"id"]);
// NSLog(#"Image URL is: %#", [[value objectForKey:#"reward_definitions"] objectForKey:#"image_url"]);
//if ( [array isKindOfClass:[NSDictionary class]] ) {
badgeY1 = badgeY1 +200;
badgeY2 = badgeY2 +200;
badgeY3 = badgeY3 +200;
missionCount = missionCount+1;
}
NSLog(#"While loops done");
for (int a; missionCount > 4; a = a+1) {
missionsScroll.contentSize = CGSizeMake(776, missionsScroll.contentSize.height+200);
}
Nothing is showing up in the scroll view.
It's not obvious what is happening, but first things to check are where the views are valid (not nil) and that this code is running on the main thread.
Put these in and post the results.
NSLog(#"missionsScroll: %#", (missionsScroll==nil)?#"NIL":#"OK");
NSLog(#"progressView: %#", (progressView==nil)?#"NIL":#"OK");
NSLog(#"missionName: %#", (missionName==nil)?#"NIL":#"OK");
NSLog(#"mainThread: %#", ([NSThread isMainThread])?#"OK":#"Background Thread");
Your code is quite convoluted and very difficult to read. Perhaps you could check if your complicated coordinates calculations work as expected, e.g.
NSLog(#"Frame of badge %#", NSStringFromCGRect(badge.frame));
How many times are your while loops iterating? The outer loop increases the y-position of your labels. But the labels will only be displayed at the end of the run loop / start of the next run loop. If you exit this method with the labels with a high y-value then you'll not see them. (It doesn't matter how many times you change the y-value while you're running this code. The display will only update when it's all done.)
** Correction ** You seem to be adding new views each time around your while loop. So in fact I'd expect you to have multiple copies of the subviews appearing when they finally get displayed.
(There's a lot of code to wade through here. If my answer is way off, you might get better answers, but trimming back some of the code and isolating the issue.)

Array out of bounds and slow slow app

So below is my code for my controller, which I have four of one for each tab on the tab bar. I have two issues.
I am getting an array out bounds but I can't chase it down. Am I missing something here?
Second when my app starts up it take 5 - 8 seconds before it loads the first view of the tab bar. Once it loads and I click another tab, the tab doesn't turn blue and the app sits there for 3 seconds then finally switches. I am a noob and am struggling here. I think this issue might be fixed by fetching the data in another thread or something? I am sure this controller is full of bugs.
import "AllMackTableViewController.h"
import "PostDetailViewController.h"
import "MackdabMobileAppDelegate.h"
import <QuartzCore/QuartzCore.h>
import "Post.h"
define FONT_SIZE 14.0f
define CELL_CONTENT_WIDTH 254.0f
define CELL_CONTENT_MARGIN 5.0f
#implementation AllMackTableViewController
#synthesize jsonArray;
#synthesize localJsonArray;
#synthesize postDetailViewController;
#synthesize allPostsTableView;
#synthesize fetchedResultsController, managedObjectContext;
#synthesize minuteTimer;
#synthesize regionsTimer;
pragma mark
pragma mark View lifecycle
(void)viewDidLoad {
[super viewDidLoad];
self.title = NSLocalizedString(#"Feed", #"You're Matching Posts");
UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(refresh)];
self.navigationItem.rightBarButtonItem = refreshButton;
allPostsTableView.delegate = self;
[refreshButton release];
[self refresh];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
(void)scrollViewDidScroll:(UIScrollView *) scrollView;
{
CGFloat scrollHeight = scrollView.contentSize.height;
CGPoint p = scrollView.contentOffset;
//NSLog(#"x = %f, y = %f", p.x, p.y);
}
(void)viewWillAppear:(BOOL)animated {
/*
Set up two timers, one that fires every minute, the other every fifteen minutes.
1/ The time displayed for each time zone must be updated every minute on the minute.
2/ Time zone data is cached. Some time zones are based on 15 minute differences from GMT, so update the cache every 15 minutes, on the "quarter".
*/
NSTimer *timer;
NSDate *date = [NSDate date];
/*
Set up a timer to update the table view every minute on the minute so that it shows the current time.
*/
NSDate *oneMinuteFromNow = [date dateByAddingTimeInterval:60];
NSCalendarUnit unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
NSDateComponents *timerDateComponents = [calendar components:unitFlags fromDate:oneMinuteFromNow];
// Add 1 second to make sure the minute update has passed when the timer fires.
[timerDateComponents setSecond:1];
NSDate *minuteTimerDate = [calendar dateFromComponents:timerDateComponents];
timer = [[NSTimer alloc] initWithFireDate:minuteTimerDate interval:60 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
self.minuteTimer = timer;
[timer release];
}
pragma mark
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.localJsonArray count];
NSLog(#"Setting numberOfRowsInSection to %i",[self.localJsonArray count]);
if ( [jsonArray count] < 9 ) {
return [self.localJsonArray count];
NSLog(#"Setting numberOfRowsInSection to %i inside of non add one.",[self.localJsonArray count]);
} else {
return [self.localJsonArray count] + 1;
}
}
(void)updateTime:(NSTimer *)timer {
/*
To display the current time, redisplay the time labels.
Don't reload the table view's data as this is unnecessarily expensive it recalculates the number of cells and the height of each item to determine the total height of the view etc. The external dimensions of the cells haven't changed, just their contents.
*/
NSArray *visibleCells = self.tableView.visibleCells;
for (PostTableCustomCellController *cell in visibleCells) {
[cell redisplay];
}
[self updateRegions];
}
(NSString *)dateDiff:(NSString *)origDate {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setFormatterBehavior:NSDateFormatterBehavior10_4];
[df setDateFormat:#"EEE, dd MMM yy HH:mm:ss VVVV"];
NSDate *convertedDate = [df dateFromString:origDate];
[df release];
NSDate *todayDate = [NSDate date];
double ti = [convertedDate timeIntervalSinceDate:todayDate];
ti = ti * 1;
if(ti < 1) {
return #"never";
} else if (ti < 60) {
return #"less than a minute ago";
} else if (ti < 3600) {
int diff = round(ti / 60);
return [NSString stringWithFormat:#"%d minutes ago", diff];
} else if (ti < 86400) {
int diff = round(ti / 60 / 60);
return[NSString stringWithFormat:#"%d hours ago", diff];
} else if (ti < 2629743) {
int diff = round(ti / 60 / 60 / 24);
return[NSString stringWithFormat:#"%d days ago", diff];
} else {
return #"never";
}
}
(void)updateRegions {
/*
The following sets the date for the regions, hence also for the time zone wrappers. This has the sideeffect of "faulting" the time zone wrappers (see TimeZoneWrapper's setDate: method), so can be used to relieve memory pressure.
*/
NSDate *date = [NSDate date];
for (Post *post in localJsonArray) {
post.timeRemaining = [self dateDiff:post.deadline];
}
}
// Customize the appearance of table view cells.
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UILabel *distance;
UIImage *image = [UIImage imageNamed:#"imageA.png"];
static NSString *CellIdentifier = #"customCell"; // This is identifier given in IB jason set this.
PostTableCustomCellController *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (indexPath.row != [localJsonArray count] ) {
if (cell == nil) {
NSLog(#"Cell created");
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"PostTableCustomCellController" owner:nil options:nil];
for(id currentObject in nibObjects)
{
if([currentObject isKindOfClass:[PostTableCustomCellController class]])
{
cell = (PostTableCustomCellController *)currentObject;
}
}
}
Post *post = [localJsonArray objectAtIndex:indexPath.row];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy"];
//Optionally for time zone converstions
//[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"..."]];
NSString *stringFromDate = [formatter stringFromDate:post.deadline];
cell.authorName.text = post.author;
cell.deadline.text = stringFromDate;
cell.budget.text = post.budget;
cell.description.text = post.description;
[[cell avatar] setImage:[UIImage imageNamed:#"butterfly.jpeg"]];
[stringFromDate release];
NSLog([NSString stringWithFormat:#"%#", post.distance]);
if([#"" isEqualToString: post.distance] || nil == post.distance) {
cell.distance.text = #"1 mi.";
}else{
cell.distance.text = #"25 mi.";
}
Post *myPost = [localJsonArray objectAtIndex:[indexPath row]];
// Might can remove these
UILabel *locationLabel = (UILabel *) [cell distance];
UITextView *postTextView = (UITextView *) [cell description];
//CGSize maximumLabelSize = CGSizeMake(254,88.0f);
NSString *text;
CGSize constraint;
CGSize size;
CGFloat height;
CGFloat realHeight;
CGSize expectedLabelSize;
text = myPost.description;
constraint = CGSizeMake(CELL_CONTENT_WIDTH (CELL_CONTENT_MARGIN * 2), 88.0f);
size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
height = MAX(size.height, 35.0f);
realHeight = height + 36.0f (10);
expectedLabelSize = [text sizeWithFont:[UIFont boldSystemFontOfSize:18.0f] constrainedToSize:CGSizeMake(252.0f, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];
CGRect newFrame = postTextView.frame;
newFrame.size.height = expectedLabelSize.height;
newFrame.size.width = 252;
postTextView.frame = newFrame;
[[cell description] sizeToFit];
[[cell viewForBackground] sizeToFit];
[cell setNeedsDisplay];
}// Ok, all done for filling the normal cells, next we probaply reach the +1 index, which doesn’t contain anything yet
if ( [jsonArray count] == 9 ) { // Only call this if the array count is 25
if(indexPath.row == [localJsonArray count] ) { // Here we check if we reached the end of the index, so the +1 row
if (cell == nil) {
cell = [[[PostTableCustomCellController alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Reset previous content of the cell, I have these defined in a UITableCell subclass, change them where needed
cell.authorName.text = nil;
cell.deadline.text = nil;
cell.budget.text = nil;
cell.description.text = nil;
// Here we create the ‘Load more’ cell
UILabel *loadMore =[[UILabel alloc]initWithFrame: CGRectMake(20,0,362,100)];
loadMore.textColor = [UIColor blackColor];
loadMore.highlightedTextColor = [UIColor darkGrayColor];
loadMore.backgroundColor = [UIColor clearColor];
loadMore.font=[UIFont fontWithName:#"Verdana" size:20];
loadMore.textAlignment=UITextAlignmentCenter;
loadMore.font=[UIFont boldSystemFontOfSize:20];
loadMore.text=#"Load More..";
[cell addSubview:loadMore];
}
}
return cell;
}
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (indexPath.row != [localJsonArray count] ) {
Post *myPost = [localJsonArray objectAtIndex:[indexPath row]];
NSString *text = myPost.description;
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH (CELL_CONTENT_MARGIN * 2), 88.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = MAX(size.height, 35.0f);
return height + (CELL_CONTENT_MARGIN * 2) + 28.0f;
}else{
return 100.0f;
}
}
(IBAction)nextTwentyFivePlease:(NSString *)thePostID{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.jsonArray = [Post findNextTwentyFiveRemote:thePostID];
if (self.localJsonArray == nil) {
self.localJsonArray = [[NSMutableArray alloc]init]; // init the local array if it’s empty
}
[self.localJsonArray addObjectsFromArray:self.jsonArray];
[self.tableView reloadData];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
(IBAction)refresh {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.jsonArray = [Post findAllRemote];
if (self.localJsonArray == nil) {
self.localJsonArray = [[NSMutableArray alloc]init]; // init the local array if it’s empty
}
[self.localJsonArray addObjectsFromArray:self.jsonArray];
//self.localJsonArray = [Post findAllRemote];
[self.tableView reloadData];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
pragma mark
pragma mark Table view delegate
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ( [jsonArray count] == 9 ) { // only check for the load more function if we have 25 results in the dynamic array
if (indexPath.row == [localJsonArray count] ) { // See if we reached the +1 in the results
Post *tempPost = [jsonArray objectAtIndex:indexPath.row];
NSLog('What is at tempPost');
[self nextTwentyFivePlease:tempPost.postID]; // function to load more results
}
} else {
NSInteger row = [indexPath row];
if (self.postDetailViewController == nil) {
PostDetailViewController *aPostDetail = [[PostDetailViewController alloc] initWithNibName:#"PostDetailView" bundle:nil];
self.postDetailViewController = aPostDetail;
postDetailViewController.post = [localJsonArray objectAtIndex:row];
[aPostDetail release];
}
postDetailViewController.title = [NSString stringWithFormat:#"Details"];
MackdabMobileAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.allMacksNavController pushViewController:postDetailViewController animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
pragma mark
pragma mark Timer set accessor methods
(void)setMinuteTimer:(NSTimer *)newTimer {
if (minuteTimer != newTimer) {
[minuteTimer invalidate];
minuteTimer = newTimer;
}
}
(void)setRegionsTimer:(NSTimer *)newTimer {
if (regionsTimer != newTimer) {
[regionsTimer invalidate];
regionsTimer = newTimer;
}
}
pragma mark
pragma mark Memory management
(void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
(void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
(void)dealloc {
[allPostsTableView release];
[postDetailViewController release];
[localJsonArray release]; // may need to remove this
[super dealloc];
}
#end
In your refresh method which is called in viewDidLoad, it appears that it is doing a bunch of network access to download some information. That would explain why it is taking so long to show your initial tab.
You'll want to do that network access in a background thread so that your UI doesn't block. Then once you've gotten the results back you can update your UI from the main thread. Something like:
- (IBAction) refresh {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self performSelectorInBackground:#selector(refreshInBackground) withObject:nil];
}
- (void) refreshInBackground {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
self.jsonArray = [Post findAllRemote];
if (self.localJsonArray == nil) {
self.localJsonArray = [[NSMutableArray alloc]init]; // init the local array if it’s empty
}
[self.localJsonArray addObjectsFromArray:self.jsonArray];
[self performSelectorOnMainThread:#selector(refreshComplete) withObject:nil waitUntilDone:NO];
}
- (void) refreshComplete {
[self.tableView reloadData];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
EDIT: As Rob noted in the comment below, you'll want to add some kind of flag (or semaphore) to avoid firing off multiple -refresh calls at the same time. Threading and race conditions are always a tricky bit, but my goal above was just to get you moving in the right direction so that you can use background threads for your network calls.

UIImage problem

I am loading the images of size 450KB in UIImage view and then adding it to UIscrollview. while am scrolling the 30 images continously,its getting crashed.. what may be the reason..is this memory leak issue...or image size is the problem...? thanks in advance..
here is my code ..
#try{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
//NSArray *array = [global_ContentString componentsSeparatedByString:#"###"];
NSArray *array1 = [catalogURL componentsSeparatedByString:#"&"];
//**NSLog(#"array1****** = %#",array1);
NSLog(#"loading catalog image(method: loadCatalogImage).......%#%#",baseURL, [[[array1 objectAtIndex:0] componentsSeparatedByString:#"##"] objectAtIndex:0]);
//NSLog(#"baseURL = %#",baseURL);
NSLog(#"loading catalog image.......%#%#",baseURL, [[[array1 objectAtIndex:0] componentsSeparatedByString:#"##"] objectAtIndex:0]);
zoomedImageURL = [NSString stringWithFormat:#"%#%#", baseURL, [[[array1 objectAtIndex:0] componentsSeparatedByString:#"##"] objectAtIndex:1]];
[zoomedImageURL retain];
NSLog(#"aaaaaaaaaaaaaa = %#",zoomedImageURL);
//UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",baseURL, [[[array1 objectAtIndex:0] componentsSeparatedByString:#"##"] objectAtIndex:0]]]]];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",zoomedImageURL]]]];
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.image = img;//[GPSTripTracking generatePhotoThumbnail:img:109];
[pool release];
[global_imgProgress stopAnimating];
}
#catch (NSException *e) {
[global_imgProgress stopAnimating];
NSLog(#"Exception....");
}
#finally {
}
am releasing my imgView in dealloc method..
i imlemented the following code in "scrollviewdidscroll"
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
if (pageControlUsed) {
// do nothing - the scroll was initiated from the page control, not the user dragging
//pageText.text = [NSString stringWithFormat:#"%d/%d", (pageControl.currentPage +1), pageControl.numberOfPages];
pageText.text = [NSString stringWithFormat:#"%d/%d", (pageControl.currentPage ), pageControl.numberOfPages];
//NSLog(#"not scrollling page....");
return;
}
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
//NSLog(#"scrolling page....%d", page);
// A possible optimization would be to unload the views+controllers which are no longer visible
}
and my code for " loadScrollViewWithPage" is
- (void)loadScrollViewWithPage:(int)page
{
//page--;
if (page < 0) return;
if (page >= numberOfPages) return;
if(!isViewCatalog && searchId == 1)
{
//NSLog(#"curre page = %d",pageControl.currentPage);
NSArray *array1 = [global_ContentString componentsSeparatedByString:#"###"];
if(searchInCatalogFlag == 1)
{
pageControl.currentPage=0;
NSArray *urlArray = [[array1 objectAtIndex:pageControl.currentPage] componentsSeparatedByString:#"##"];
//NSLog(#"url array** = %#",urlArray);
headerText.text = [NSString stringWithString:[urlArray objectAtIndex:0]];
pageText.text = [NSString stringWithFormat:#"%d/%d", pageControl.currentPage, (pageControl.numberOfPages - 1)];
}
else
{
NSArray *urlArray = [[array1 objectAtIndex:pageControl.currentPage] componentsSeparatedByString:#"##"];
//NSLog(#"url array** = %#",urlArray);
headerText.text = [NSString stringWithString:[urlArray objectAtIndex:0]];
pageText.text = [NSString stringWithFormat:#"%d/%d", pageControl.currentPage, (pageControl.numberOfPages - 1)];
}
if(page == selectedPage && ![global_imgProgress isAnimating])
[global_imgProgress startAnimating];
}
else
{
headerText.text = [NSString stringWithString:global_SelectedCatalogName];
pageText.text = [NSString stringWithFormat:#"%d/%d", (pageControl.currentPage + 1), (pageControl.numberOfPages - 1)];
if(page == selectedPage + 1 && ![global_imgProgress isAnimating] )
[global_imgProgress startAnimating];
// NSLog(#"header text = %#", headerText.text);
//headerText.text = [NSString stringWithString:[urlArray objectAtIndex:0]];
}
FullPageView *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null] ) {
//NSLog(#"Loading page =========== %d, %d", page, selectedPage);
//voucherPageNo = page;
//[voucherImage retain];
if(universalApp==2)
{
controller = [[FullPageView alloc] initWithNibName:#"FullPageView_iphone" bundle:nil];//:page];
[controller.view setFrame:CGRectMake(0, 0, 320,332)];
}
else
{
controller = [[FullPageView alloc] initWithNibName:#"FullPageView" bundle:nil];//:page];
[controller.view setFrame:CGRectMake(0, 192, 768, 691)];
}
//[controller.view setFrame:CGRectMake(0, 0, 320,480)];
//[controller.view setFrame:CGRectMake(0, 192, 768, 691)];
if((!isViewCatalog && searchId < 2 && searchInCatalogFlag == 0))// || searchInCatalogFlag == 1)
{
// NSLog(#">>>>>>>>>>>>>>>>>> LOADING IMAGE >>>>>>>>>>>>>>>>>>>>");
[controller setPageNo:page];
// if(page >= selectedPage - 1)
[NSThread detachNewThreadSelector:#selector(loadImage) toTarget:controller withObject:nil];
}
else //if((page >= (selectedPage - 1) && page <= (selectedPage + 1)) || !isFirstTimeLoading)
{
NSLog(#"Loading CATALOG IMAGE = %d, %d, %#", page, selectedPage, (isFirstTimeLoading ?#"YES" : #"NO"));
[controller setCatalogURL:[NSString stringWithFormat:#"%#", [catalogArray objectAtIndex:page+(searchId< 2 && !isViewCatalog && searchInCatalogFlag == 0?0:1)]]];
NSLog(#"loading image ipad= %#", [catalogArray objectAtIndex:page+(searchId< 2 && !isViewCatalog && searchInCatalogFlag == 0?0:1)]);
// if(page >= selectedPage - 1)
[NSThread detachNewThreadSelector:#selector(loadCatalogImage) toTarget:controller withObject:nil];
// if(page == (selectedPage + 1))
//isFirstTimeLoading = NO;
}
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
// add the controller's view to the scroll view
if (nil == controller.view.superview)
{
// NSLog(#"Voucher view addead at page..... %d", page);
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
// NSLog(#">>>>>>>>> %f, %f", frame.size.width, frame.origin.x);
[scrollView addSubview:controller.view];
}
//if(page == pageControl.currentPage)
//[imgProgress startAnimating];
//else
//pageControlUsed = YES;
}
where wil be the problem..?
450KB is the compressed image size. When an image is loaded into memory, it is uncompressed.
A rule of thumb for working out how much memory an uncompressed image will occupy is:
width * height * 4
With 30 images it is very likely that you're running out of memory.
You should write your code to only keep images in memory if they are visible on screen.
It very likely that your program gets terminated by iOS because it consumes too much memory. Start it from XCode and look at the console - it will probably print that it receives memory warnings.
You will have to load the images on demand, i.e. only when the user gets close to seeing them, and you will have to release the ones that move out of view again. To that end, implement the
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
delegate method, look at the scroll view's content offset and load/release the appropriate images. Alternatively, you can choose to not release them there but instead wait for a memory warning to do so. To do so, implement the
- (void)didReceiveMemoryWarning
method in your view controller.
This might be the issue of memory leaks.
Try to replace this line
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",zoomedImageURL]]]]
and use this
UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",zoomedImageURL]]]];
<<<<<YOUR CODE>>>>
[img release];
I hope this helps

build and analyze not working in my project

In my iPhone Project when i select build and analyze (shift + mac + A ) it will give me all potential memory leak in my project... but in my current project it is not working... when i intentionally put a memory leak and select build and analyze... it doesn't give me any potential memory leak as analyzer result
if i write
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:6];
NSMutableArray *tempArrayfinal = [[NSMutableArray alloc] initWithCapacity:12];
and doesn't release it... it is not giving me any potential leak but if i write
NSString *leakyString = [[NSString alloc] initWithString:#"Leaky String "];
NSLog(#"%#",leakyString);
here it gives me potential leak as analyzer result...why it is not giving potential leak in NSMutableArray and why it gives potential leak in NSString ?... how can i rely on Build and analyze for memory leak...
I've run the app with Leak tool and it is showing me leak in tempArray and tempArrayfinal
Here is my function
- (void)viewDidLoad
{
[super viewDidLoad];
maxOnSnaxAppDelegate *delegate = (maxOnSnaxAppDelegate *)[[UIApplication sharedApplication] delegate];
lblMessage.tag = MESSAGE_LABEL;
lblGuess.tag = GUESS_LABEL;
lblScore.tag = SCORE_LABEL;
self.gameCompleteView.tag = FINAL_SCORE_VIEW;
lblFinalScore.tag = FINAL_SCORE_LABEL;
lblGuess.text = #"";
lblMessage.text = #"";
lblScore.text = #"";
int row = 0;
int column = 0;
maxImagrArray = [[NSMutableArray alloc] init];
for(UIView *subview in [self.view subviews]) {
if([subview isKindOfClass:[CustomImageView class]])
{
[subview removeFromSuperview];
}
}
for(int i = 0 ; i < 12 ; i++)
{
if(i%3 == 0 && i != 0)
{
row++;
column = -1;
}
if(i != 0 )
{
column++;
//row = 0;
}
CustomImageView *tempImageView = [[CustomImageView alloc] initWithImage:[UIImage imageNamed:#"max-img.png"]];
tempImageView.frame = CGRectMake((column*tempImageView.frame.size.width) + 45, (row*tempImageView.frame.size.height)+ 60, tempImageView.frame.size.width, tempImageView.frame.size.height);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, tempImageView.bounds);
[self.view addSubview:tempImageView];
tempImageView.tag = i+1;
tempImageView.userInteractionEnabled = YES;
[maxImagrArray addObject:tempImageView];
[tempImageView setIndex:i];
[tempImageView release];
}
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:6];
NSMutableArray *tempArrayfinal = [[NSMutableArray alloc] initWithCapacity:12];
for(int i = 0 ; i < 12 ; i++)
{
if(i < 6)
{
int temp = (arc4random() % 10) + 1;
NSString *tempStr = [[NSString alloc] initWithFormat:#"%d",temp];
[tempArray insertObject:tempStr atIndex:i];
[tempArrayfinal insertObject:tempStr atIndex:i];
[tempStr release];
}
else
{
int temp = (arc4random() % [tempArray count]);
[tempArrayfinal insertObject: (NSString *)[tempArray objectAtIndex:temp] atIndex:i];
//int index = [(NSString *)[tempArray objectAtIndex:temp] intValue];
[tempArray removeObjectAtIndex:temp];
}
CustomImageView *tmpCustom = [maxImagrArray objectAtIndex:i];
tmpCustom.frontImageIndex = [(NSString *)[tempArrayfinal objectAtIndex:i] intValue];
NSLog(#"%d",tmpCustom.frontImageIndex);
}
[maxImagrArray release];
delegate.time = 60.0;
timer = nil;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
delegate.view = self.view;
//[tempArray release];
//[tempArrayfinal release];//these 2 lines are deliberately commented to see
//...it is not showing any potential memory leak though....
delegate.viewController = self;
}
please help...
[tempArray insertObject:tempStr atIndex:i];
[tempArrayfinal insertObject:tempStr atIndex:i];
are the culprits... when i uncomment these 2 lines.. it stops giving me the warning... i don't know why...
You shouldn't really rely on the Build and Analyze tool. It does not always catch all leaks. Threre is no substitute for following the memory management rules from apple (apart from garbage collection on OS X). However, I'm not sure why it isn't catching such a simple leak. I tried at line in a method and it did give me a result. Are you sure its not in an if statement, because I've found that sometimes in an if statement it won't correct you.