iOS 7 Blur ImageView Behind TableView - ios

I have a table view with an image view behind it. I'm trying to figure out how to blur the image behind the table view similar to how it looks when you open control center.
Here is my view:
And here is the code for it:
#import "ToursAndConferencesViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "WebViewController.h"
#import "DTCustomColoredAccessory.h"
#import "SVProgressHUD.h"
#implementation ToursAndConferencesViewController
{
UIActivityIndicatorView *loadingIndicator;
}
#synthesize webViewController;
- (void)viewDidLoad
{
UIImageView *background = [[UIImageView alloc]init];
background.image = [UIImage imageNamed:#"plain_app-background.png"];
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
[self.tableView setBackgroundView:background];
self.title = #"Tours & Conferences";
[[SVProgressHUD appearance]setHudBackgroundColor:[UIColor blackColor]];
[[SVProgressHUD appearance]setHudForegroundColor:[UIColor whiteColor]];
[SVProgressHUD showWithStatus:#"Loading"];
// [SVProgressHUD showWithStatus:#"Loading" maskType:SVProgressHUDMaskTypeGradient];
}
- (void)viewDidDisappear:(BOOL)animated
{
[SVProgressHUD dismiss];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"%# found a %# element", self, elementName);
if ([elementName isEqual:#"channel"])
{
// If the parser saw a channel, create new instance, store in our ivar
channel = [[RSSChannel alloc]init];
// Give the channel object a pointer back to ourselves for later
[channel setParentParserDelegate:self];
// Set the parser's delegate to the channel object
[parser setDelegate:channel];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// return 0;
NSLog(#"channel items %d", [[channel items]count]);
return [[channel items]count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return nil;
UIImageView *image = [[UIImageView alloc]init];
image.image = [UIImage imageNamed:#"CellImage.png"];
UIImageView *background = [[UIImageView alloc]init];
background.image = [UIImage imageNamed:#"plain_app-background.png"];
UIImageView *highlightedCellImage = [[UIImageView alloc]init];
highlightedCellImage.image = [UIImage imageNamed:#"HighlightedCellImage"];
UIColor *kfbBlue = [UIColor colorWithRed:8.0/255.0f green:77.0/255.0f blue:139.0/255.0f alpha:1];
UIColor *kfbLightBlue = [UIColor colorWithRed:24.0/255.0f green:89.0/255.0f blue:147.0/255.0f alpha:1];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"UITableViewCell"];
cell.textLabel.font=[UIFont systemFontOfSize:16.0];
}
RSSItem *item = [[channel items]objectAtIndex:[indexPath row]];
[[cell textLabel]setText:[item title]];
NSLog(#"Date: %#", [item date]);
tableView.backgroundColor = [UIColor clearColor];
[self.tableView setSeparatorColor:kfbBlue];
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.highlightedTextColor = kfbBlue;
cell.textLabel.font = [UIFont fontWithName:#"FranklinGothicStd-ExtraCond" size:20.0];
cell.textLabel.textColor = kfbLightBlue;
// cell.backgroundView = image;
cell.backgroundColor = [UIColor clearColor];
// cell.selectedBackgroundView = highlightedCellImage;
tableView.backgroundView = background;
DTCustomColoredAccessory *accessory = [DTCustomColoredAccessory accessoryWithColor:cell.textLabel.textColor];
accessory.highlightedColor = kfbBlue;
cell.accessoryView =accessory;
return cell;
}
- (void)fetchEntries
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc]init];
// Construct a URL that will ask the service for what you want -
// note we can concatenate literal strings together on multiple lines in this way - this results in a single NSString instance
NSURL *url = [NSURL URLWithString:#"http://kyfbnewsroom.com/category/conferences/feed"];
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc]initWithRequest:req delegate:self startImmediately:YES];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
[self fetchEntries];
}
return self;
}
// This method will be called several times as the data arrives
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[xmlData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
/* We are just checking to make sure we are getting the XML
NSString *xmlCheck = [[NSString alloc]initWithData:xmlData encoding:NSUTF8StringEncoding];
NSLog(#"xmlCheck = %#", xmlCheck);*/
// [loadingIndicator stopAnimating];
[SVProgressHUD dismiss];
// Create the parser object with the data received from the web service
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
// Give it a delegate - ignore the warning here for now
[parser setDelegate:self];
//Tell it to start parsing - the document will be parsed and the delegate of NSXMLParser will get all of its delegate messages sent to it before this line finishes execution - it is blocking
[parser parse];
// Get rid of the XML data as we no longer need it
xmlData = nil;
// Reload the table.. for now, the table will be empty
[[self tableView]reloadData];
NSLog(#"%#\n %#\n %#\n", channel, [channel title], [channel infoString]);
}
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
// Release the connection object, we're done with it
connection = nil;
// Release the xmlData object, we're done with it
xmlData = nil;
[SVProgressHUD dismiss];
// Grab the description of the error object passed to us
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
// Create and show an alert view with this error displayed
UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[webViewController webView]loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
// Push the web view controller onto the navigation stack - this implicitly creates the web view controller's view the first time through
// [[self navigationController]pushViewController:webViewController animated:YES];
[self.navigationController pushViewController:webViewController animated:YES];
// Grab the selected item
RSSItem *entry = [[channel items]objectAtIndex:[indexPath row]];
// Construct a URL with the link string of the item
NSURL *url = [NSURL URLWithString:[entry link]];
// Construct a request object with that URL
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Load the request into the web view
[[webViewController webView]loadRequest:req];
webViewController.hackyURL = url;
// Set the title of the web view controller's navigation item
// [[webViewController navigationItem]setTitle:[entry title]];
}
#end

Set your tableView to [UIColor clearColor];
Then download apple's UIImage+ImageEffects category files that contain helper methods to blur images.
You can follow this tutorial for code samples on image blurring
Here is my final result which is an image behind my tableView:

Related

UILabels are Hidding behind the Image View cell?

Hi I have issue with Labels ,i.e , I have a XML NewsViewController where i am displaying the News . You can see the Screen shot (NewsViewController.jpg) In NewsViewController i am displaying the Tittle, Date and Description labels , those labels are hiding behind the imageView cell But in the Few News List are displaying fine .Can any one Help me ??
Below i have given the NewsViewController code please check
Here is my NewsViewController.m
#import "NewsViewController.h"
#import "NewsTableViewCell.h"
#import "NewDetailsViewController.h"
#import <SDWebImage/UIImageView+WebCache.h>
#interface NewsViewController ()
{
NSString *temString;
NSMutableString *strTemp;
BOOL isDateSearch;
}
#end
#implementation NewsViewController
#synthesize arrImages;
#synthesize TittleOne;
#synthesize TittleTwo;
#synthesize TittleThree;
#synthesize datepicker;
#synthesize PickerContainer;
#synthesize datepickerTittle;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
#pragma mark - View Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[TittleOne setFont: [UIFont fontWithName:#"GEEast-ExtraBold" size:12]];
[TittleTwo setFont: [UIFont fontWithName:#"GEEast-ExtraBold" size:10]];
[TittleThree setFont: [UIFont fontWithName:#"GEEast-ExtraBold" size:10]];
// [[UIColor redColor] set];
[datepickerTittle setFont:[UIFont fontWithName:#"GEEast-ExtraBold" size:12]];
// [datepickerTittle.textColor= [UIColor yellowColor]];
isDateSearch=NO;
self.arrTitles =[[NSMutableArray alloc] init];
self.arrDescription=[[NSMutableArray alloc]init];
self.arrImages=[[NSMutableArray alloc]init];
self.arrDate=[[NSMutableArray alloc]init];
self.arrUrls=[[NSMutableArray alloc]init];
self.arrDateSearch=[[NSMutableArray alloc]init];
//[self performSelectorInBackground:#selector(requestingForNews:) withObject:nil];
// dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), s^{
self.spinnerView.hidden=YES;
[self makeRequestForNews];
// self.spinnerView.stopAnimating;
//});
// Do any additional setup after loading the view.
[self imagedownloader:#"http://www.shura.bh/MediaCenter/News/"];
}
-(void)requestingForNews:(id)sender
{
[self makeRequestForNews];
}
-(void) imagedownloader : (NSString *)urlStringOfImage
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
//downlaod image
NSURL *imageUrl = [NSURL URLWithString:urlStringOfImage];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50 )];
imageView.image = image;
[self.view addSubview:imageView];
});
});
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - make request for news
-(void)makeRequestForNews
{
NSURL *url =[NSURL URLWithString:self.strNewsApi];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//After making request the apparent thing is expecting the response that may be expected response or an Error. so create those objects and intialize them with NULL.
NSURLResponse *response = NULL;
NSError *requestError =NULL;
//Once you have response with you , Capture YOur Responce data using NsData.
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
//Convert the respnse Data into Response String.
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
//Now We can start parsing the Data using XMl parser . you need XML parser in-order to use the below class method "dictionaryFOrXMLString".
NSError *parserError = NULL;
//XML parsing
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:responseData];
[xmlParser setDelegate:self];
[xmlParser parse];
// NSURL *url = [NSURL URLWithString:url];
// NSData *data = [NSData dataWithContentsOfURL:url];
// UIImage *image = [UIImage imageWithData:data];
//NSDictionary *xmlDict = [XMLReader dictionaryForXMLString:responseString error:NULL];
//once you have xmlDict handy, you can pass this to the any ViewController (Like table view) to populate the Data.
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"ShuraNews"])
{
}
if ([elementName isEqualToString:#"PUBLISHINGPAGEIMAGE"])
{
}
strTemp=[NSMutableString new];
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
//temString =string;
[strTemp appendString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"TITLE"])
{
NSLog(#"temstring=== %#", strTemp);
[self.arrTitles addObject:strTemp];
}
if ([elementName isEqualToString:#"PUBLISHINGPAGECONTENT"])
{
NSLog(#"temstring=== %#", strTemp);
[self.arrDescription addObject:strTemp];
}
if ([elementName isEqualToString:#"NEWSARTICLEDATE"])
{
NSLog(#"temstring=== %#", strTemp);
[self.arrDate addObject:strTemp];
}
if ([elementName isEqualToString:#"PUBLISHINGPAGEIMAGE"])
{
NSLog(#"temstring=== %#", strTemp);
[self.arrImages addObject:strTemp];
}
if ([elementName isEqualToString:#"ShuraNews"])
{
[self.tblNews reloadData];
// self.spinnerView.hidden=YES;
}
if ([elementName isEqualToString:#"URL"])
{
[self.arrUrls addObject:strTemp];
}
}
#pragma mark - TabeView Datasource//delegate method
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (isDateSearch)
{
return [self.arrDateSearch count];
}
else{
return [self.arrTitles count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView setSeparatorInset:UIEdgeInsetsZero];
static NSString *cellIdentifier=#"cellNews";
NewsTableViewCell *cell=(NewsTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[NewsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
// cell.NewsTableViewCell.textColor = UIColorFromRGB(0x000000);
cell.backgroundColor=[UIColor clearColor];
}
if( [indexPath row] % 2){
cell.contentView.backgroundColor =UIColorFromRGB(0Xffffff);
}
else{
cell.contentView.backgroundColor =UIColorFromRGB (0Xdcdcdc);
}
//selectbackground color start
UIView *NewsTableViewCell = [[UIView alloc] initWithFrame:cell.frame];
NewsTableViewCell.backgroundColor = UIColorFromRGB(0Xdcdcdc);
cell.selectedBackgroundView = NewsTableViewCell; //select background colro end
cell.lblTitles.font = [UIFont fontWithName:#"GEEast-ExtraBold" size:12];
if (isDateSearch)
{
cell.lblTitles.text=[[self.arrDateSearch objectAtIndex:indexPath.row]objectForKey:#"title"];
}
else{
cell.lblTitles.text=[self.arrTitles objectAtIndex:indexPath.row];
}
cell.lblDescription.font =[UIFont fontWithName:#"GE SS Unique" size:12];
cell.lblDate.font=[UIFont fontWithName:#"GE SS Unique" size:12];
if (isDateSearch)
{
cell.lblDescription.text=[[self.arrDateSearch objectAtIndex:indexPath.row]objectForKey:#"des"];
}
else{
cell.lblDescription.text=[self.arrDescription objectAtIndex:indexPath.row];
}
cell.lblDate.text=[self.arrDate objectAtIndex:indexPath.row];
cell.lblTitles.textAlignment= NSTextAlignmentRight;
cell.lblDate.textAlignment = NSTextAlignmentRight;
cell.lblDescription.textAlignment = NSTextAlignmentRight;
//SDWebImage Code for lazy loader
[cell.imgNews setImageWithURL:[NSURL URLWithString:[self.arrImages objectAtIndex:indexPath.row]] placeholderImage:[UIImage imageNamed:#""]];
// cell.imgNews.image=[UIImage imageWithData:data];
cell.imgNews.layer.borderColor = [UIColor blackColor].CGColor;
cell.imgNews.layer.borderWidth = 2.0;
[PickerContainer setHidden:YES];
if (!cell.imgNews.image)
{
cell.lblTitles.frame=CGRectMake(cell.lblTitles.frame.origin.x, cell.lblTitles.frame.origin.y, 283, cell.lblTitles.frame.size.height);
cell.lblDate.frame=CGRectMake(cell.lblDate.frame.origin.x, cell.lblDate.frame.origin.y, 286, cell.lblDate.frame.size.height);
cell.lblDescription.frame=CGRectMake(cell.lblDescription.frame.origin.x, cell.lblDescription.frame.origin.y, 281, cell.lblDescription.frame.size.height);
cell.imgNews.layer.borderColor = [UIColor blackColor].CGColor;
cell.imgNews.layer.borderWidth = 0;
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dict=nil;
if (isDateSearch)
{
//dict=[[NSDictionary alloc]initWithObjectsAndKeys:[NSString stringWithFormat:#"%#",[[self.arrDateSearch objectAtIndex:indexPath.row]objectForKey:#"title"]],#"title",[NSString stringWithFormat:#"%#",[[self.arrDateSearch objectAtIndex:indexPath.row]objectForKey:#"des"]],#"img",[NSString stringWithFormat:#"%#",[self.arrDescription objectAtIndex:indexPath.row]],#"Des",[NSString stringWithFormat:#"%#",[self.arrUrls objectAtIndex:indexPath.row]],#"url", nil];
}
else{
dict=[[NSDictionary alloc]initWithObjectsAndKeys:[NSString stringWithFormat:#"%#",
[self.arrTitles objectAtIndex:indexPath.row]],#"title",[NSString stringWithFormat:#"%#",
[self.arrImages objectAtIndex:indexPath.row]],#"img",[NSString stringWithFormat:#"%#",
[self.arrDescription objectAtIndex:indexPath.row]],#"Des",[NSString stringWithFormat:#"%#",[self.arrUrls objectAtIndex:indexPath.row]],#"url", nil];
}
[self performSegueWithIdentifier:#"NewsDetailsID" sender:dict];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"NewsDetailsID"])
{
((NewDetailsViewController *)segue.destinationViewController).strTitle=[sender objectForKey:#"title"];
((NewDetailsViewController *)segue.destinationViewController).strDetailImage=[sender objectForKey:#"img"];
((NewDetailsViewController *)segue.destinationViewController).strDescription=[sender objectForKey:#"Des"];//strUrl
((NewDetailsViewController *)segue.destinationViewController).strUrl=[sender objectForKey:#"url"];
}
}
- (IBAction)backBtnClicked:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
- (IBAction)DatePickerBt:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
PickerContainer.frame = CGRectMake(0, 150, 320, 261);
[PickerContainer setHidden:NO];
}
- (IBAction)HideButton:(id)sender
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
PickerContainer.frame = CGRectMake(0,600, 320, 261);
[UIView commitAnimations];
if ([self.arrDateSearch count])
{
[self.arrDateSearch removeAllObjects];
}
if ([self.arrDate count])
{
for (int i=0; i<[self.arrDate count]; i++)
{
NSLog(#"arrdate === %#",self.arrDate);
NSArray *arrDateStr=[[self.arrDate objectAtIndex:i] componentsSeparatedByString:#" "];
NSArray *arrDat=[[NSString stringWithFormat:#"%#",[arrDateStr objectAtIndex:0]] componentsSeparatedByString:#"/"];
NSString *strDat=[NSString stringWithFormat:#"%#-%#-%#",[arrDat objectAtIndex:2],[arrDat objectAtIndex:1],[arrDat objectAtIndex:0]];
NSString *strPicDat=[[[NSString stringWithFormat:#"%#",self.datepicker.date]componentsSeparatedByString:#" "]objectAtIndex:0];
NSLog(#" strpic date === %#",strPicDat);
if ([strDat isEqualToString:strPicDat])
{
isDateSearch=YES;
NSDictionary *dictTemp=[NSDictionary dictionaryWithObjectsAndKeys:[self.arrTitles objectAtIndex:i],#"title",[self.arrDescription objectAtIndex:i],#"des",[self.arrImages objectAtIndex:i],#"img", nil];
[self.arrDateSearch addObject:dictTemp];
NSLog(#"dates equal");
}
}
[self.tblNews reloadData];
}
}
- (IBAction)ReloadButton:(id)sender {
}
#end
Below i have given the Screen shots
NewsViewController Link Here
DetailsViewController Link here
There are two questions here. Ill answer the one about the tableview.
The SDWebImage category on UIImageView (UIImageView+WebCache) is an async API , hence when you work out whether there is an image there and arrange your text frame it always evaluates to NO
[cell.imgNews setImageWithURL:[NSURL URLWithString:[self.arrImages objectAtIndex:indexPath.row]] placeholderImage:[UIImage imageNamed:#""]];
...
if (!cell.imgNews.image)
{
//setup text frame
}
what you are calling is a convenience method for this...
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock;
so try this...
[cell.imgNews setImageWithURL:[NSURL URLWithString:[self.arrImages objectAtIndex:indexPath.row]]
placeholderImage:[UIImage imageNamed:#""]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
...
if (image) {
//setup text frame for image
}
else {
//setup text for no image as cell is recycled and may have held image previously
}
}];
Please view your InterfaceBuilder Screenshots 2 and 3.
The Large image (3) has the autoresizing mask set so that the margin to the right is maintained. #
It looks like this
_ | _
The Label besides the small image in the UITableViewCell however only mainains the margins to the top and the left. Set to keep it on the right as well and it won't overflow anymore.
Make it look like the mask above.
Of course you'd have to do this for all 3 labels. Alternatvively you could wrap the 3 labels in a view and only do the autoresizing mask stuff for this container and make the labels fill out the entire width of the container.
I will answer the question regarding the cells in "NewsViewController".
Using [UIImage imageNamed:#""] is equivalent to passing nil. UIImage class will not find an image with a name of empty string, so it will return nil.
When you check cell.imgNews's image, it will be nil as the real image is still not loaded yet.
You have two options:
1- Use a placeholder image.
2- Check for the image url instead of the image itself. like if (![self.arrImages objectAtIndex:indexPath.row]).
Note: Make sure the data arrays have the same length. If one of them has different length, you will get out of bounds exception. One way of solving this is using a custom class that hold all related information. Then build an array of it.

RSS Feed Won't Load

I have a tableview that shows data from an RSS feed and it works fine as long as it is not the root view of my app. I have always shown it by pressing a button but now I'm wanting to have it be the first view the user sees but the activity indicator just keeps spinning and the content never loads. Like I said, when I've pushed it onto the navigation stack from a button, it loads the content so I'm not really sure why it won't load when it's the first view shown.
AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
AgStoriesViewController *rootView = [[AgStoriesViewController alloc] initWithNibName:nil bundle:nil];
WebViewController *wvc = [[WebViewController alloc]init];
[rootView setWebViewController:wvc];
KFBNavControllerViewController *navController = [[KFBNavControllerViewController alloc] initWithRootViewController:rootView];
navController.delegate = rootView;
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
}
TableView with RSS
#import "AgStoriesViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "WebViewController.h"
#import "DTCustomColoredAccessory.h"
#import "UIImage+ImageEffects.h"
#import "UIView+Borders.h"
#import "TSMessage.h"
#import "TSMessageView.h"
#import "ArticleCell.h"
#import "KFBAppDelegate.h"
#import "MenuTableViewController.h"
#implementation AgStoriesViewController
{
UIActivityIndicatorView *loadingIndicator;
}
#synthesize webViewController, blurredView, contentView, menuShown;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.navigationController.delegate = self;
}
return self;
}
- (void)viewDidLoad
{
menuShown = NO;
UIImage *background = [UIImage imageNamed:#"sunset"];
UIImageView *backgroundImageView = [[UIImageView alloc]initWithImage:background];
CGFloat width = CGRectGetWidth(self.view.bounds);
CGFloat height = CGRectGetHeight(self.view.bounds);
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
self.tableView.backgroundView = backgroundImageView;
self.title = #"Ag News";
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
UIImage *hamburgerButton = [UIImage imageNamed:#"list_button"];
UIBarButtonItem *listButton = [[UIBarButtonItem alloc]initWithImage:hamburgerButton style:UIBarButtonItemStyleBordered target:self action:#selector(showMenu)];
self.navigationItem.leftBarButtonItem = listButton;
}
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
loadingIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(width / 2, height / 2, 37, 37)];
loadingIndicator.center = CGPointMake(width / 2, height / 2 - 37);
}
else
{
loadingIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(142, 365, 37, 37)];
}
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
loadingIndicator.hidesWhenStopped = YES;
[self.tableView addSubview:loadingIndicator];
[loadingIndicator startAnimating];
}
- (void)showMenu
{
if (!menuShown)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
UIColor *kfbBlue = [UIColor colorWithRed:8.0/255.0f green:77.0/255.0f blue:139.0/255.0f alpha:1];
contentView = [[UIView alloc]initWithFrame:self.tableView.bounds];
contentView.autoresizesSubviews = YES;
contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
contentView.backgroundColor = [UIColor clearColor];
blurredView = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
[blurredView setBarStyle:UIBarStyleBlack];
[blurredView setBarTintColor:kfbBlue];
MenuTableViewController *menu = [[MenuTableViewController alloc]initWithNibName:#"MenuTableViewController" bundle:nil];
menu.view.frame = CGRectMake(0, 0, screenWidth, screenHeight - 50);
[self.view addSubview:contentView];
[contentView addSubview:blurredView];
[self addChildViewController:menu];
[contentView addSubview:menu.view];
self.tableView.scrollEnabled = NO;
menuShown = YES;
}
else if (menuShown)
{
[contentView removeFromSuperview];
[blurredView removeFromSuperview];
self.navigationController.navigationBarHidden = NO;
self.tableView.scrollEnabled = YES;
menuShown = NO;
}
}
- (void)closeMenu
{
[contentView removeFromSuperview];
self.navigationController.navigationBarHidden = NO;
self.tableView.scrollEnabled = YES;
}
- (void)viewDidDisappear:(BOOL)animated
{
[loadingIndicator stopAnimating];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"%# found a %# element", self, elementName);
if ([elementName isEqual:#"channel"])
{
channel = [[RSSChannel alloc]init];
[channel setParentParserDelegate:self];
[parser setDelegate:channel];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"channel items %lu", (unsigned long)[[channel items]count]);
return [[channel items]count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 215;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RSSItem *item = [[channel items]objectAtIndex:[indexPath row]];
ArticleCell *cell = [tableView dequeueReusableCellWithIdentifier:#"articleCell"];
if (!cell)
{
NSArray *nibs =[[NSBundle mainBundle] loadNibNamed:#"ArticleCell" owner:self options:NULL];
cell = [nibs firstObject];
}
cell.articleTitle.text = [item title];
cell.articleDescription.text = [item infoString];
cell.articleTitle.textColor = [UIColor whiteColor];
cell.articleDescription.textColor = [UIColor whiteColor];
cell.articleTitle.font = [UIFont fontWithName:#"FranklinGothicStd-ExtraCond" size:22.0];
cell.articleDescription.font = [UIFont fontWithName:#"FranklinGothicStd-ExtraCond" size:16.0];
cell.backgroundColor = [UIColor clearColor];
return cell;
}
- (void)fetchEntries
{
xmlData = [[NSMutableData alloc]init];
NSURL *url = [NSURL URLWithString:#"http://kyfbnewsroom.com/category/ag-news/feed"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc]initWithRequest:req delegate:self startImmediately:YES];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
[self fetchEntries];
}
return self;
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[xmlData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
[loadingIndicator stopAnimating];
UIImage *background = [UIImage imageNamed:#"sunset"];
UIImage *effectImage = [background applyDarkEffect];
UIImageView *blurredBackground = [[UIImageView alloc]init];
blurredBackground.image = effectImage;
self.tableView.backgroundView = blurredBackground;
// Create the parser object with the data received from the web service
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
// Give it a delegate
[parser setDelegate:self];
//Tell it to start parsing - the document will be parsed and the delegate of NSXMLParser will get all of its delegate messages sent to it before this line finishes execution - it is blocking
[parser parse];
// Get rid of the XML data as we no longer need it
xmlData = nil;
NSMutableArray *actionAlerts = [NSMutableArray array];
for (RSSItem *object in channel.items)
{
if (object.isActionAlert)
{
[actionAlerts addObject:object];
}
}
for (RSSItem *object in actionAlerts)
{
[channel.items removeObject:object];
}
// Reload the table
[[self tableView]reloadData];
NSLog(#"%#\n %#\n %#\n", channel, [channel title], [channel infoString]);
}
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
// Release the connection object, we're done with it
connection = nil;
// Release the xmlData object, we're done with it
xmlData = nil;
[loadingIndicator stopAnimating];
// Grab the description of the error object passed to us
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
// Create and show an alert view with this error displayed
// UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// [av show];
[TSMessage showNotificationWithTitle:#"Network Error" subtitle:errorString type:TSMessageNotificationTypeError];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
[[webViewController webView]loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
[self.navigationController pushViewController:webViewController animated:YES];
RSSItem *entry = [[channel items]objectAtIndex:[indexPath row]];
NSURL *url = [NSURL URLWithString:[entry link]];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[[webViewController webView]loadRequest:req];
webViewController.hackyURL = url;
}
else
{
[[webViewController webView]loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
NSMutableArray *details = [self.splitViewController.viewControllers mutableCopy];
UINavigationController *detailNav = [[UINavigationController alloc]initWithRootViewController:webViewController];
[details replaceObjectAtIndex:1 withObject:detailNav];
KFBAppDelegate *appDelegate = (KFBAppDelegate *)[[UIApplication sharedApplication]delegate];
appDelegate.splitViewController.viewControllers = details;
appDelegate.window.rootViewController = self.splitViewController;
appDelegate.splitViewController.delegate = webViewController;
[appDelegate.splitViewController viewWillAppear:YES];
// Grab the selected item
RSSItem *entry = [[channel items]objectAtIndex:[indexPath row]];
// Construct a URL with the link string of the item
NSURL *url = [NSURL URLWithString:[entry link]];
// Construct a request object with that URL
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Load the request into the web view
[[webViewController webView]loadRequest:req];
webViewController.hackyURL = url;
// Set the title of the web view controller's navigation item
[[webViewController navigationItem]setTitle:[entry title]];
}
}
#end
Use this method to reload your table data -
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
[[self tableView]reloadData];
}
This method is called when parsing of your xml document is finished. You are reloading table when data is not properly set in array, so it is showing you empty table.
EDIT -
Call connection method properly on view Initialization.
fetchEntries needs to be called in viewDidLoad.

Implement Pull to Refresh for RSS Feed [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have an RSS feed in my app and I'm trying to figure out how to implement pull to refresh. Here is my code:
#import "ActionAlertsViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "WebViewController.h"
#import "DTCustomColoredAccessory.h"
#import "SVProgressHUD.h"
#implementation ActionAlertsViewController
{
UIActivityIndicatorView *loadingIndicator;
}
#synthesize webViewController;
- (void)viewDidLoad
{
UIImageView *background = [[UIImageView alloc]init];
background.image = [UIImage imageNamed:#"plain_app-background.png"];
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
[self.tableView setBackgroundView:background];
self.title = #"Action Alerts";
[[SVProgressHUD appearance]setHudBackgroundColor:[UIColor blackColor]];
[[SVProgressHUD appearance]setHudForegroundColor:[UIColor whiteColor]];
[SVProgressHUD showWithStatus:#"Loading"];
}
- (void)viewDidDisappear:(BOOL)animated
{
[SVProgressHUD dismiss];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"%# found a %# element", self, elementName);
if ([elementName isEqual:#"channel"])
{
// If the parser saw a channel, create new instance, store in our ivar
channel = [[RSSChannel alloc]init];
// Give the channel object a pointer back to ourselves for later
[channel setParentParserDelegate:self];
// Set the parser's delegate to the channel object
[parser setDelegate:channel];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// return 0;
NSLog(#"channel items %d", [[channel items]count]);
return [[channel items]count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return nil;
UIImageView *image = [[UIImageView alloc]init];
image.image = [UIImage imageNamed:#"CellImage.png"];
UIImageView *background = [[UIImageView alloc]init];
background.image = [UIImage imageNamed:#"plain_app-background.png"];
UIImageView *highlightedCellImage = [[UIImageView alloc]init];
highlightedCellImage.image = [UIImage imageNamed:#"HighlightedCellImage"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"UITableViewCell"];
cell.textLabel.font=[UIFont systemFontOfSize:16.0];
}
RSSItem *item = [[channel items]objectAtIndex:[indexPath row]];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"EEE, dd MMM yyyy HH:mm:ssZ"];
NSDate *pubDate = [formatter dateFromString:[item date]];
[formatter setDateStyle:NSDateFormatterMediumStyle];
NSString *dateString = [formatter stringFromDate:pubDate];
NSLog(#"Date String: %#", dateString);
[[cell textLabel]setText:[item title]];
[[cell detailTextLabel]setText:dateString];
NSLog(#"Date: %#", [item date]);
tableView.backgroundColor = [UIColor clearColor];
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.highlightedTextColor = [UIColor blueColor];
cell.textLabel.font = [UIFont fontWithName:#"FranklinGothicStd-ExtraCond" size:20.0];
cell.textLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
cell.detailTextLabel.highlightedTextColor = [UIColor blueColor];
cell.detailTextLabel.font = [UIFont fontWithName:#"FranklinGothicStd-ExtraCond" size:14.0];
cell.detailTextLabel.textColor = [UIColor whiteColor];
cell.backgroundView = image;
cell.selectedBackgroundView = highlightedCellImage;
tableView.backgroundView = background;
DTCustomColoredAccessory *accessory = [DTCustomColoredAccessory accessoryWithColor:cell.textLabel.textColor];
accessory.highlightedColor = [UIColor blueColor];
cell.accessoryView =accessory;
return cell;
}
- (void)fetchEntries
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc]init];
// Construct a URL that will ask the service for what you want
NSURL *url = [NSURL URLWithString:#"http://kyfbnewsroom.com/category/public-affairs/notifications/feed/"];
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc]initWithRequest:req delegate:self startImmediately:YES];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
[self fetchEntries];
}
return self;
}
// This method will be called several times as the data arrives
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[xmlData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
/* We are just checking to make sure we are getting the XML
NSString *xmlCheck = [[NSString alloc]initWithData:xmlData encoding:NSUTF8StringEncoding];
NSLog(#"xmlCheck = %#", xmlCheck);*/
[SVProgressHUD dismiss];
// Create the parser object with the data received from the web service
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
[parser setDelegate:self];
[parser parse];
// Get rid of the XML data as we no longer need it
xmlData = nil;
// Reload the table.. for now, the table will be empty
NSMutableArray *notActionAlerts = [NSMutableArray array];
for (RSSItem *object in channel.items) {
if (!object.isActionAlert) {
[notActionAlerts addObject:object];
}
}
for (RSSItem *object in notActionAlerts) {
[channel.items removeObject:object];
}
[[self tableView]reloadData];
NSLog(#"%#\n %#\n %#\n", channel, [channel title], [channel infoString]);
}
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
// Release the connection object, we're done with it
connection = nil;
// Release the xmlData object, we're done with it
xmlData = nil;
[SVProgressHUD dismiss];
// Grab the description of the error object passed to us
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
// Create and show an alert view with this error displayed
UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[webViewController webView]loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
// Push the web view controller onto the navigation stack - this implicitly creates the web view controller's view the first time through
// [[self navigationController]pushViewController:webViewController animated:YES];
[self.navigationController pushViewController:webViewController animated:YES];
// Grab the selected item
RSSItem *entry = [[channel items]objectAtIndex:[indexPath row]];
// Construct a URL with the link string of the item
NSURL *url = [NSURL URLWithString:[entry link]];
// Construct a request object with that URL
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Load the request into the web view
[[webViewController webView]loadRequest:req];
webViewController.hackyURL = url;
// Set the title of the web view controller's navigation item
// [[webViewController navigationItem]setTitle:[entry title]];
}
#end
If you're using storyboard for that you have native support for pull-to-refresh.
Only change Refreshing to enabled and then you can hook up an action for this event.

iOS UITableView content not loading - Property access result unused

I'm trying to load a table with content from Twitter. The table is in a UIView and being created in the drawRect()...but I keep getting a warning:
Property access result unused - getters should not be used for side effects
on each.
Nothing show up in my table.
Here's my .h file:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <Twitter/Twitter.h>
#import "ColorController.h"
#interface TwitterController : UIView <UITableViewDelegate, UITableViewDataSource> {
UIButton* btnCloseView;
UITableView* tblTweets;
UIImageView* imgTwitterIcon;
ColorController* colorManager;
NSMutableArray* tweetsArray;
NSString* twitterID;
}
#property (nonatomic, retain) NSString* twitterID;
- (void) getTweets;
- (void) closeWin;
#end
and my .m
#import "TwitterController.h"
#implementation TwitterController
#synthesize twitterID;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
colorManager = [ColorController new];
}
return self;
}
- (void)drawRect:(CGRect)rect {
imgTwitterIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"imgTwitterBird"]];
CGRect twitterIconFrame = [imgTwitterIcon frame];
twitterIconFrame.origin.x = 50.0;
twitterIconFrame.origin.y = 20.0;
tblTweets = [[UITableView alloc] initWithFrame:CGRectMake(50.0, 25.0, 220.0, 500.0)];
tblTweets.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
tblTweets.separatorColor = [colorManager setColor:176.0:196.0:222.0];
tblTweets.layer.borderWidth = 1.0;
tblTweets.rowHeight = 20.0;
tblTweets.scrollEnabled = YES;
tblTweets.delegate.self;
tblTweets.dataSource.self;
UIImage* imgCloseButton = [UIImage imageNamed:#"btnCloseWindow.png"];
CGSize imageSize = imgCloseButton.size;
btnCloseView = [[UIButton alloc] initWithFrame: CGRectMake(220.0, 550.0, imageSize.width, imageSize.height)];
[btnCloseView setImage:[UIImage imageNamed:#"btnCloseWindow.png"] forState:UIControlStateNormal];
[btnCloseView addTarget:self action:#selector(closeWin:) forControlEvents:UIControlEventTouchUpInside];
[self getTweets];
[self addSubview:tblTweets];
[self addSubview:imgTwitterIcon];
[self addSubview:btnCloseView];
}
- (void) getTweets {
//array to hold tweets
tweetsArray = [[NSMutableArray alloc] init];
///set up a NSURL to the twitter API
NSURL* twitterAPI = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=%#&count=10", twitterID]];
//get last 10 tweets (max is 20)
TWRequest *twitterRequest = [[TWRequest alloc] initWithURL:twitterAPI
parameters:nil requestMethod:TWRequestMethodGET];
// Notice this is a block, it is the handler to process the response
[twitterRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if ([urlResponse statusCode] == 200) {
// The response from Twitter is in JSON format
// Move the response into a dictionary and print
NSError *error;
NSDictionary *tweetsDict = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
for(NSDictionary* thisTweetDict in tweetsDict) {
[tweetsArray addObject:[thisTweetDict objectForKey:#"text"]];
}
[tblTweets reloadData];
}
else
NSLog(#"Twitter error, HTTP response: %i", [urlResponse statusCode]);
}];
}
#pragma mark Table Management
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [tweetsArray count];
NSLog(#"%i", [tweetsArray count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tweetsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"tableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.textColor = [UIColor colorWithRed:66.0/255.0 green:66.0/255.0 blue:66.0/255.0 alpha:1];
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size: 13.0];
cell.textLabel.text = [tweetsArray objectAtIndex:indexPath.row];
CGRect cellFrame = [cell frame];
cellFrame.size.height = 25.0;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString* thisTweet = [tweetsArray objectAtIndex:indexPath.row];
}
#pragma mark Close Window
- (void) closeWin {
NSMutableDictionary* userData = [[NSMutableDictionary alloc] init];
[userData setObject:#"closeTwitter" forKey:#"theEvent"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"theMessenger" object:self userInfo: userData];
}
#end
drawRect is used to draw stuff inside this views, using drawing functions
You should move your views additions to the layoutSubviews
Instead of - (void)drawRect:(CGRect)rect use - (void)layoutSubviews
This may or may not solve your issues, but nevertheless its the correct approach

Memory management in viewDidUnload - should I nil both array and objects inside?

I have a tableview to load news from internet. I and trying to nil all properties in viewDidUnload.
- (void)viewDidUnload
{
self.newsArray = nil;
self.newsTableView = nil;
self.indicatorView = nil;
// self.iconDownLoader = nil;
self.downloadArray = nil;
[super viewDidUnload];
}
Every time the app crash in viewDidUnload. If I comment self.iconDownLoader = nil;, it will be fine. So can any one tell me why does this happen? Thanks you.
---------------------NewsViewController.m--------------------------
//
// NewsViewController.m
//
// Created by on 18/01/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "NewsViewController.h"
#import "ASIHTTPRequest.h"
#import "SBJson.h"
#import "NewsModel.h"
#import "NewsDetailViewController.h"
#define kCustomRowCount 6
#define IconPlaceHolder #"Spinner"
#implementation NewsViewController
#synthesize appDelegate, newsTableViewCell, newsTableView, indicatorView;
#synthesize iconDownLoader, newsArray, downloadArray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// setup appDelegate
self.appDelegate = (SydneyAppDelegate *)[[UIApplication sharedApplication] delegate];
// initial arrays
self.newsArray = [[NSMutableArray alloc] init];
self.downloadArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
if(self.appDelegate.reachable) {
[self getNews];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Connection" message:#"No Internet connection. Please try again later." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
- (void)viewDidUnload
{
self.newsArray = nil;
self.newsTableView = nil;
self.indicatorView = nil;
// self.iconDownLoader = nil;
self.downloadArray = nil;
[super viewDidUnload];
}
#pragma mark - ASIHTTPRequest
- (void) getNews
{
NSURL *url = [NSURL URLWithString:#"http://ferrarimaseratisydney.com/api/getPublicNews.html"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void) requestFinished:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
NSArray *json = [responseString JSONValue];
for (id aNewsInJson in json)
{
NewsModel *aNews = [[NewsModel alloc] initWithJson:aNewsInJson];
[self.newsArray addObject:aNews];
}
[self.indicatorView removeFromSuperview];
[self.newsTableView reloadData];
}
- (void) requestFailed:(ASIHTTPRequest *)request
{
NSError *error;
error = [request error];
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Navigation logic may go here. Create and push another view controller.
NewsDetailViewController *newsDetailViewController = [[NewsDetailViewController alloc] init];
// transform news array
newsDetailViewController.news = [self.newsArray objectAtIndex:indexPath.row];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:newsDetailViewController animated:YES];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.newsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"NewsCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"NewsTableViewCell" owner:self options:nil];
cell = self.newsTableViewCell;
self.newsTableViewCell = nil;
}
// read from newsModel
NewsModel *news = [self.newsArray objectAtIndex:indexPath.row];
UILabel *label;
label = (UILabel *)[cell viewWithTag:10];
label.text = [NSString stringWithString:news.title];
label = nil;
label = (UILabel *)[cell viewWithTag:11];
label.text = [NSString stringWithString:news.description];
UIImageView *imageView = (UIImageView *)[cell viewWithTag:12];
imageView.image = news.image;
if (news.image == nil)
{
imageView.image = [UIImage imageNamed:IconPlaceHolder];
self.iconDownLoader = [[IconDownLoader alloc] init];
self.iconDownLoader.url = news.imageUrl;
self.iconDownLoader.delegate = self;
self.iconDownLoader.indexPath = indexPath;
if (self.appDelegate.ip4 == YES)
{
self.iconDownLoader.width = 300;
self.iconDownLoader.height = 150;
}
else
{
self.iconDownLoader.width = 150;
self.iconDownLoader.height = 75;
}
[self.downloadArray addObject:self.iconDownLoader];
[self.iconDownLoader start];
}
return cell;
}
#pragma mark - IconDownLoaderDelegate
- (void)iconDownLoadFinsh:(NSData *)imageData row:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.newsTableView cellForRowAtIndexPath:indexPath];
UIImageView *imageView = (UIImageView *)[cell viewWithTag:12];
if (imageData != 0)
{
imageView.image = [UIImage imageWithData:imageData];
}
else
{
imageView.image = [UIImage imageNamed:#"icon57"];
}
NewsModel *newsModel = [self.newsArray objectAtIndex:indexPath.row];
newsModel.image = [UIImage imageWithData:imageData];
}
#end
-----------------------IconDownLoader.m-------------------
//
// IconDownLoader.m
//
// Created by on 24/11/11.
// Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//
#import "IconDownLoader.h"
#import "ASIHTTPRequest.h"
#implementation IconDownLoader
#synthesize delegate = _delegate;
#synthesize url = _url;
#synthesize indexPath = _indexPath;
#synthesize width = _width;
#synthesize height = _height;
#synthesize request = _request;
- (void)start {
NSString *originalString = #"width=%s&height=%s";
NSString *newString = [NSString stringWithFormat:#"width=%d&height=%d&type=jpg", self.width, self.height];
NSString *resizedURL = [self.url stringByReplacingOccurrencesOfString:originalString withString:newString];
NSURL *url = [NSURL URLWithString:[resizedURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
_request = [ASIHTTPRequest requestWithURL:url];
if (_indexPath) {
_request.userInfo = [NSDictionary dictionaryWithObject:_indexPath forKey:#"indexPath"];
}
[_request setDelegate:self];
[_request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request {
NSInteger statusCode = request.responseStatusCode;
switch (statusCode) {
case 401: // Not Authorized: either you need to provide authentication credentials, or the credentials provided aren't valid.
break;
case 200: {
NSData *responseData = [request responseData];
if (!responseData) {
UIAlertView *alertView;
alertView = [[UIAlertView alloc] initWithTitle:#"Oops" message:[NSString stringWithFormat:#"Download failed in row %d", _indexPath.row] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
return;
}
[_delegate iconDownLoadFinsh:responseData row:[request.userInfo objectForKey:#"indexPath"]];
}
break;
default:{
}
}
}
- (void)dealloc {
if (_request != nil) {
[_request clearDelegatesAndCancel];
}
}
#end
Generally in viewDidUnload you should only release and zero out all references to the nib objects you own.
That said, you can destroy model objects in viewDidUnload too if they consume a lot of memory. You should remember that viewDidUnload is a counterpart to viewDidLoad, so a good rule of thumb is to destroy only those objects in viewDidUnload which you create in viewDidLoad. You should also remember that viewDidUnload is not called when the view controller is released – only when its view is.
In your case I would not release newsArray and downloadArray just because you create them in init.... I would just send them removeAllObjects instead.
As for the crash, you create a new shared icon downloader every time a cell needs an image, which is a bit awkward. If you do need a shared downloader instance, you should not recreate it for each and every cell. It looks like you want to keep all the downloaders you created in an ivar array instead because each downloader is one-shot and is responsible for loading a single image.
Not enough information here to tell, but probably you have released iconDownloader directly in some other part of the code we cannot see without setting the reference to nil at that time.
Then in viewDidUnload you are trying to release an invalid reference.
For #synthesize, use:
#synthesize iconDownLoader = _iconDownloader;
then fix all of the compiler warnings to use self.icondownloder instead of iconDownloader, and eliminate all uses of "release" (assuming your property is marked as retain which it should be).
In fact, perhaps your whole problem is that the property is not a retain property so you make the iconDOwnloader and it's promptly released.

Resources