Why does [self superview].center not refer to the center? - cocoa-touch

This code:
m_networkActivityView = [[[NSBundle mainBundle] loadNibNamed:#"NetworkActivityView" owner:self options:nil] objectAtIndex:0];
[self addSubview:m_networkActivityView];
m_networkActivityView.center = self.center;
m_networkActivityView.hidden = true;
gets me this, which is off center because it's centered on the table, not the screen:
while this code
m_networkActivityView = [[[NSBundle mainBundle] loadNibNamed:#"NetworkActivityView" owner:self options:nil] objectAtIndex:0];
[self addSubview:m_networkActivityView];
m_networkActivityView.center = [self superview].center;
m_networkActivityView.hidden = true;
gets me this:
which I really don't understand.

I checked the superview as recommneded in a comment, and it was null, which is why it was showing up in the corner. So I did this to fix it:
m_networkActivityView.center =
CGPointMake([UIScreen mainScreen].bounds.size.width / 2,
[UIScreen mainScreen].bounds.size.height / 2);

Related

Loading views from NIB to use as pages in a scrollview cancels autolayout

I've searched this issue, but did not managed to find a working answer.
I need to show a paging scrollview that shows some views loaded from .xib files, here's my code:
This is the init code for TutorialPage.m, subclass of UIView:
- (id)initWithFrame:(CGRect)frame andPage:(int) page
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"tutorial page %d initialized", page);
switch (page) {
case 0:
self.view = [[[NSBundle mainBundle] loadNibNamed:#"TutorialPage01View" owner:self options:nil] objectAtIndex:0];
break;
case 1:
self.view = [[[NSBundle mainBundle] loadNibNamed:#"TutorialPage02View" owner:self options:nil] objectAtIndex:0];
break;
default:
break;
}
NSLog(#"frame %g %g, %g %g", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
[self addSubview:self.view];
}
return self;
}
The pages are added to the scrollview as follows, the code below is part of TutorialViewController.m, that has a valid scrollview outlet:
- (void)viewDidLayoutSubviews
{
NSLog(#"tutorial view loaded");
self.scrollView.scrollEnabled = YES;
self.scrollView.pagingEnabled = YES;
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height);
for (int i = 0 ; i < 2 ; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIView *subview = [[TutorialPage01 alloc] initWithFrame:frame andPage:i];
[self.scrollView addSubview:subview];
}
}
The layouts are divided in two halves, vertically. And each half has constraints to make it match the container view and have equal heights.
THE PROBLEM IS
When the views are added to the scrollview they kinda ignore the autolayout, and the subview that should have a size of (290, 538), presents itself as (320,568), so it invades the other pages.
Is it possible to add constraints in the .xib file and then have then applied to the superview it is added, in code?
Thanks in advance!
This is a quick and dirty way to do it. Since you're adding a new frame programmatically, you should also ensure that the view you are replacing conforms to the frame you are initiating.
- (id)initWithFrame:(CGRect)frame andPage:(int) page
{
self = [super initWithFrame:frame];
if (self) {
UIView *view = [[[NSBundle mainBundle] loadNibNamed:#"TutorialView" owner:self options:nil] objectAtIndex:0];
view.frame = self.frame;
[self addSubview:view];
}
return self;
}
This seemed to work for me in a much simpler app I built based on your code.

image in cell overlaying text

The image seems to overlay the text in the cell, I'm not sure why this is happening but I'd like the text to go over the image. Any help is greatly appreciated.
This is how my code looks like.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
CGRect imageFrame = CGRectMake(0, 0, 120, 90);
self.customImage = [[UIImageView alloc] initWithFrame:imageFrame];
[cell.contentView addSubview:self.customImage];
[self.customImage release];
CGRect contentFrame = CGRectMake(100, 2, 198, 30);
UILabel *title = [[UILabel alloc] initWithFrame:contentFrame];
title.tag = 0011;
title.numberOfLines = 2;
title.font = [UIFont boldSystemFontOfSize:12];
[cell.contentView addSubview:title];
[title release];
}
UILabel *title = (UILabel *)[cell.contentView viewWithTag:0011];
title.text = [currentFeed title];
NSString *directoryPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSURL *imgURL = [currentFeed thumbnailURL];
NSArray *parts = [[NSString stringWithFormat:#"%#", imgURL] componentsSeparatedByString:#"/"];
NSString *imageName = [parts objectAtIndex:[parts count]-2];
NSString *filePath = [directoryPath stringByAppendingPathComponent:imageName];
UIImage *myview = [UIImage imageWithContentsOfFile:filePath];
if(myview){
cell.imageView.image = myview;
}else{
NSData* imageDataTemp = [[NSData alloc] initWithContentsOfURL:[currentFeed thumbnailURL]];
if(imageDataTemp){
cell.imageView.image = [UIImage imageWithData:imageDataTemp];
}else{
cell.imageView.image = [UIImage imageNamed:#"youtubeLogo.png"];
}
}
return cell;
}
cell.imageView.image is not your self.customImage you added.Now it displayes the tableview cel default imageview in cell
self.customImage = [[UIImageView alloc] initWithFrame:imageFrame];
[cell.contentView addSubview:self.customImage];
[self.customImage setTag:12345];
[self.customImage release];
and get the added custom imageview as
UIImageView *imageVW=[cell viewWithTag:12345];
and use this imageview to set image later in the code instead of cell.imageview

cell label text changes on selection after scroll

I am having an issue with tableview cells that are created from 2 different prototype cells. I add my own labels and images to them.
They load fine, but after i scroll in the tableview, and then select a cell, the labels from other cells are getting added to the labels already present in the cell.
I've read about similar issues people are having but none address the fact that it only occurs on selection.
I have tried adding if (cell == nil){}; but that has no effect.
My cellForRowAtIndexPath is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"NDSClassSubMenuViewController cellForRowAtIndexPath: running...");
NDSClassAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSDictionary *childNodes = [appDelegate.children objectAtIndex:0];
NSString *multicellstat = [childNodes objectForKey:#"#CELLTYPE"];
NSLog(#"Multicellstat %#", multicellstat);
NSLog(#"TESTING CHILD %#", childNodes);
//ONLY LOADING SUB MENU OPTIONS
NSString *cellType;
if (multicellstat == NULL){
NSLog(#"cellForRowAtIndexPath: #CellType == multicell. Making multicell.");
cellType = #"SegueCellSubmenu";
}else {
NSLog(#"cellForRowAtIndexPath: children variable is NOT NULL. Making MenuCell.");
cellType = #"SegueCellMulti";
}
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellType forIndexPath:indexPath];
if (multicellstat == NULL){
NSLog(#"Not adding picture.");
}else {
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
UIView *blackBG = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 60, 60)];
blackBG.backgroundColor = [UIColor grayColor];
NSURL *imageURL = [NSURL URLWithString:[childNodes objectForKey:#"#THUMBNAIL"]];
NSData *data = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:data];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, 60, 60);
int borderWidth = 1;
imageView.frame = CGRectMake(borderWidth, borderWidth, blackBG.frame.size.width-borderWidth*2, blackBG.frame.size.height-borderWidth*2);
dispatch_async(dispatch_get_main_queue(), ^{
[cell addSubview:blackBG];
[blackBG addSubview:imageView];
});
});
}
//NSDictionary *tweet = [[[[appDelegate.menuItems objectForKey:#"Table"] objectForKey:#"Parent"]objectAtIndex:indexPath.row] objectForKey:#"Child"];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(70, 10, 210, 30)];
UILabel *detailText = [[UILabel alloc] initWithFrame:CGRectMake(70, 35, 210, 30)];
[cell.contentView addSubview:label];
[cell.contentView addSubview:detailText];
NSString *text = [[appDelegate.children objectAtIndex:indexPath.row] objectForKey:#"#MENUDESC"];
NSString *name = [[appDelegate.children objectAtIndex:indexPath.row] objectForKey:#"#MENUDESC"];
//NSLog(#"cellForRowAtIndexPath MENU ITEMS %#", text);
//Title label
label.text = NULL;
label.text = text;
[label setFont: [UIFont fontWithName:#"Arial" size:16.0]];
//Detail label
detailText.text = NULL;
detailText.text = name;
[detailText setFont: [UIFont fontWithName:#"Arial" size:12.0]];
//detailText.textColor = [UIColor colorWithRed:186.0/255.0 green:186.0/255.0 blue:186.0/255.0 alpha:1];
detailText.textColor = [UIColor grayColor];
//cell.textLabel.text = text;
//cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", name];
NSLog(#"Creating submenu item: %#", text);
NSLog(#"NDSClassSubMenuViewController: cellForRowAtIndexPath: finished.");
return cell;
}
Anyone know how I can solve this?
The key issue is that the code running synch should not assume that the cell it's modifying after the image request completes is the same cell (at the same indexPath) as when the image request began.
The correct recipe is like this:
use a cached result if we have one (so we don't do web requests every time we scroll), otherwise make an asynch request.
when the request completes, cache the result
use the original indexPath to determine if the cell is still visible. if it is, reload that indexPath. the newly cached result will now be available in cellForRowAtIndexPath.
Here's a snippet of code that describes how to correctly update at table after an asynch request. In your cellForRowAtIndexPath, check for a cached response before calling this:
// in cellForRowAtIndexPath:
NSString *urlString = [childNodes objectForKey:#"#THUMBNAIL"]
NSURL *imageURL = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:imageURL];
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
if (!cachedResponse) {
// we don't find this image/request in the cache, call asynch load
[self asynchLoad:urlString forIndexPath:indexPath];
} else {
// we got this image already, update the cell
UIImage *image = [UIImage imageWithData:cachedResponse.data];
// set the cell's UIImageView subview image to image
}
Here we load the image at urlString, cache the result, and then reload the indexPath after the load if it's still visible after the request completes:
- (void)asynchLoad:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath {
NSURL *imageURL = [NSURL URLWithString:[childNodes objectForKey:#"#THUMBNAIL"]];
NSURLRequest *request = [NSURLRequest requestWithURL:imageURL];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
// cache the response
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:self];
// important part - we make no assumption about the state of the table at this point
// find out if our original index path is visible, then update it, taking
// advantage of the cached image (and a bonus option row animation)
NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows];
if ([visiblePaths containsObject:indexPath]) {
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation: UITableViewRowAnimationFade];
// because we cached the image, cellForRow... will see it and run fast
}
}
}];
}
I solved the problem by creating my own custom cell class and using storyboard to set the layout.

Releasing an image from memory

I recently started to learn objective c and I'm making an application based on tableView, imageview and scrollView.
In tableview you press a button and the application pushes to scrollview where there's an image inside imageview. I get a problem when I tried releasing a memory from imageview (the image I loaded when pressing the button). The problem is, that the image I previously loaded is still there.
Here's the code I've got:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *headTitle = [[listContent objectAtIndex:indexPath.row] objectForKey:kItemTitleKey];
if ([headTitle isEqualToString:#"Differentialekvationer"]){
leafViewController.title = headTitle;
[[self navigationController] pushViewController:leafViewController animated:YES];
NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:#"/c.png"];
UIImage *imageToLoad = [UIImage imageWithContentsOfFile:fullpath];
leafViewController.myImageView = [[UIImageView alloc] initWithImage:imageToLoad];
leafViewController.myScrollView = [[UIScrollView alloc] initWithFrame:leafViewController.view.bounds];
[leafViewController.myScrollView addSubview:leafViewController.myImageView];
leafViewController.myScrollView.contentSize = leafViewController.myImageView.bounds.size;
[leafViewController.view addSubview:leafViewController.myScrollView];
leafViewController.myScrollView.bounces = NO;
}else if ([headTitle isEqualToString:#"Gränsvärden"]){
leafViewController.title = headTitle;
[[self navigationController] pushViewController:leafViewController animated:YES];
NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:#"/e.png"];
UIImage *imageToLoad = [UIImage imageWithContentsOfFile:fullpath];
leafViewController.myImageView = [[UIImageView alloc] initWithImage:imageToLoad];
leafViewController.myScrollView = [[UIScrollView alloc] initWithFrame:leafViewController.view.bounds];
[leafViewController.myScrollView addSubview:leafViewController.myImageView];
leafViewController.myScrollView.contentSize = leafViewController.myImageView.bounds.size;
[leafViewController.view addSubview:leafViewController.myScrollView];
leafViewController.myScrollView.bounces = NO;
}
and i tried to free the memory basically with everyting
-(void)viewDidDisappear{
leafViewController.myImageView.image = nil;
leafViewController.myScrollView = nil;
leafViewController.view = nil;
[leafViewController.myImageView release];}
I don't know what to look for and where the problem lies. Help would be much appreciated :).
P.S. Please note that I've been learning objective c for 4 days now so I'm a newbie

AQGridView: How to Init cell

I'm implementing the AQGridView based on examples who comes with it. But I'm working with xibs, and in the example, the code is:
if ( plainCell == nil )
{
plainCell = [[[ImageDemoGridViewCell alloc] initWithFrame: CGRectMake(0.0, 0.0, 200.0, 150.0)
reuseIdentifier: PlainCellIdentifier] autorelease];
plainCell.selectionGlowColor = [UIColor blueColor];
}
plainCell.image = [UIImage imageNamed: [_imageNames objectAtIndex: index]];
cell = plainCell;
}
My code looks like this:
- (AQGridViewCell *) gridView: (AQGridView *)inGridView cellForItemAtIndex: (NSUInteger) index
{
static NSString * FilledCellIdentifier = #"FilledCellIdentifier";
AQGridViewCell * cell = nil;
MagazineCell * filledCell = (MagazineCell *)[gridView dequeueReusableCellWithIdentifier: FilledCellIdentifier];
if ( filledCell == nil ) {
}
filledCell.edicaoLabel.text = [[data objectAtIndex:index] name];
cell = filledCell;
return ( cell );
}
The example InitWith CGRect, but how init the cell when I work with xibs?
Generally speaking, one doesn't init a view when loading it from XIB. You actually would do the same thing inside your if (filledCell == nil) that you would do in a UITableView (although with a AQGridViewCell instead of a UITableViewCell). So if "GridCell.xib" has your AQGridViewController as File Owner and tempCell is bound to the laid-out GridCell in IB and you've set the identifer to filledCellIdentifer, you can just do:
[[NSBundle mainBundle] loadNibNamed:#"GridCell" owner:self options:nil];
filledCell = [self.tempCell autorelease];