Memory issues with NSUserDefaults - iphone

I have spent hours trying to get my project working and I just can't get it working.
Basically, I'm trying to use NSUserDefaults to save a custom object when the user hits a save button and load all the data up when the app loads. If there is no previous NSUserDefault saved, I want to set some defaults. In the end, I am getting EXC_BAD_ACCESS when trying to load a previously-saved NSUserDefault. It works fine the first load, when setting the starting data. And the thing is, when I try to enable NSZombieEnabled and the other env vars for it, it somehow loads fine without the EXC_BAD_ACCESS. So here's what I'm working with:
[App Delegate.h]
#import <UIKit/UIKit.h>
#import "Note.h"
#interface ToDoWallAppDelegate : NSObject <UIApplicationDelegate> {
...
Note *note;
}
...
#property (retain) Note *note;
#end
[App Delegate.m]
- (void)applicationDidFinishLaunching:(UIApplication *)application {
...
note = [[Note alloc] init];
NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
NSData *noteData = [stdDefaults objectForKey:#"Note"];
if (noteData) {
self.note = (Note *)[NSKeyedUnarchiver unarchiveObjectWithData:noteData];
} else {
note.background = [UIImage imageNamed:#"Cork.jpg"];
note.picture = [UIImage imageNamed:#"Cork.jpg"];
note.font = [UIFont fontWithName:#"Helvetica" size:18.0f];
note.fontColor = [UIColor blackColor];
note.fontNameIndex = 9;
note.fontSizeIndex = 6;
note.fontColorIndex = 0;
note.backgroundIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
note.pictureIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
note.text = #"Type note here...";
}
...
}
- (void)dealloc {
...
[note release];
[super dealloc];
}
[View Controller]
- (void)saveNote {
...
NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
if (stdDefaults) {
NSData *noteData = [NSKeyedArchiver archivedDataWithRootObject:UIAppDelegate.note];
[stdDefaults setObject:noteData forKey:#"Note"];
[stdDefaults synchronize];
}
}
[Note.h]
#import <Foundation/Foundation.h>
#interface Note : NSObject <NSCoding> {
UIImage *background, *picture;
UIFont *font;
UIColor *fontColor;
int fontNameIndex, fontSizeIndex, fontColorIndex;
NSIndexPath *backgroundIndexPath, *pictureIndexPath;
BOOL customBackground;
NSString *text;
}
#property (retain) UIImage *background, *picture;
#property (retain) UIFont *font;
#property (retain) UIColor *fontColor;
#property int fontNameIndex, fontSizeIndex, fontColorIndex;
#property (retain) NSIndexPath *backgroundIndexPath, *pictureIndexPath;
#property BOOL customBackground;
#property (retain) NSString *text;
- (Note *)init;
#end
[Note.m]
#import "Note.h"
#implementation Note
#synthesize background, picture, font, fontColor, fontNameIndex, fontSizeIndex, fontColorIndex, customBackground, backgroundIndexPath, pictureIndexPath, text;
- (Note *)init {
if (self = [super init]) {
background = [[UIImage alloc] init];
picture = [[UIImage alloc] init];
font = [[UIFont alloc] init];
fontColor = [[UIColor alloc] init];
backgroundIndexPath = [[NSIndexPath alloc] init];
pictureIndexPath = [[NSIndexPath alloc] init];
text = [[NSString alloc] init];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
NSData *dataBackground = UIImagePNGRepresentation(background);
NSData *dataPicture = UIImagePNGRepresentation(picture);
[encoder encodeObject:dataBackground forKey:#"dataBackground"];
[encoder encodeObject:dataPicture forKey:#"dataPicture"];
[encoder encodeObject:font forKey:#"font"];
[encoder encodeObject:fontColor forKey:#"fontColor"];
[encoder encodeInt:fontSizeIndex forKey:#"fontSizeIndex"];
[encoder encodeInt:fontColorIndex forKey:#"fontColorIndex"];
[encoder encodeBool:customBackground forKey:#"customBackground"];
[encoder encodeObject:backgroundIndexPath forKey:#"backgroundIndexPath"];
[encoder encodeObject:pictureIndexPath forKey:#"pictureIndexPath"];
[encoder encodeObject:text forKey:#"text"];
}
- (Note *)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
NSData *dataBackground = [decoder decodeObjectForKey:#"dataBackground"];
NSData *dataPicture = [decoder decodeObjectForKey:#"dataPicture"];
background = [[UIImage imageWithData:dataBackground] retain];
picture = [[UIImage imageWithData:dataPicture] retain];
font = [[decoder decodeObjectForKey:#"font"] retain];
fontColor = [[decoder decodeObjectForKey:#"fontColor"] retain];
fontNameIndex = [decoder decodeIntForKey:#"fontNameIndex"];
fontColorIndex = [decoder decodeIntForKey:#"fontColorIndex"];
customBackground = [decoder decodeBoolForKey:#"customBackground"];
backgroundIndexPath = [[decoder decodeObjectForKey:#"backgroundIndexPath"] retain];
text = [[decoder decodeObjectForKey:#"text"] retain];
}
return self;
}
- (void)dealloc {
[super dealloc];
[background release];
[picture release];
[font release];
[fontColor release];
[backgroundIndexPath release];
[pictureIndexPath release];
[text release];
}
#end
I really need some help I appreciate it.
Edit:
Btw, there are also lines from other files that edit the App Delegate's Note object, such as:
#define UIAppDelegate ((ToDoWallAppDelegate *)[UIApplication sharedApplication].delegate)
...
UIAppDelegate.note.backgroundIndexPath = indexPath;
Edit:
This is what debugger wrote:
#0 0x90be9ed7 in objc_msgSend
#1 0x03b05210 in ??
#2 0x000023ce in -[ToDoWallAppDelegate setNote:] at ToDoWallAppDelegate.m:14
#3 0x00002216 in -[ToDoWallAppDelegate applicationDidFinishLaunching:] at ToDoWallAppDelegate.m:35
Which are:
note.text = #"Type note here...";
//and
#synthesize window, note;

I'm not sure if this is what's causing your problem, but I believe that [super dealloc] should be the LAST line of your dealloc method, not the first.

Have a look at documentation how to setup defaults
Using NSUserDefaults
If you need more info have a look in Hillega's book "Cocoa programming for Mac OS X" bignerdranch.com/books, it's explained there.
You should consider changing the headline to "How to use NSUserDefaults" ...
Example how to setup default value, in your class in initialize put something like:
+ (void)initialize{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary
dictionaryWithObject:#"YES" forKey:#"DeleteBackup"];
[defaults registerDefaults:appDefaults];
}
You could post where exactly are you getting the error instead of posting the whole code. Run it through debugger and see where it stops.

Related

Dealloc of custom object

I have this Class in my project :
#interface VideoItem : NSObject <NSCoding> {
NSString *name;
NSString *artist;
int seconds;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *imgUrl;
#property (nonatomic, retain) NSString *artist;
#end
And this is how i create this object:
VideoItem *item = [[VideoItem alloc] init];
item.name = name;
item.imgUrl = imgLink;
item.artist = artist;
And this is the dealloc:
- (void)dealloc{
[name release];
[imgUrl release];
[artist release];
[super dealloc];
}
And i want to know if this dealoc is ok with the NON-ARC? did i need to do something else because this NSString are with Property?
Edit
And if the VideoItem object was create with:
VideoItem *item = [[VideoItem alloc] init];
item.name = [NSString alloc]initWithFormat#"%#",name];
item.imgUrl = [NSString alloc]initWithFormat#"%#",imgLink];
item.artist = [NSString alloc]initWithFormat#"%#",artist];
Did in this case the dealloc is still ok? or i need to change something?
Everything looks ok, you are releasing all the #properties of your object. I would probably as well point them to nil, just to make sure, that if one of those properties is called, it will be nilled and not have a garbage value, like so:
- (void)dealloc{
[name release], name = nil;
[imgUrl release], imgUrl = nil;
[artist release], artist = nil;
[super dealloc];
}
Another thing, no related, it would be cleaner, if you would create your own init, so you can pass the properties values, when you actually create the object, like so:
-initWithName:(NSString *)name withImgURL:(NSString *)imgURL withArtist:(NSString *)artist;
Your edit:
item.name = [NSString alloc]initWithFormat#"%#",name];
item.imgUrl = [NSString alloc]initWithFormat#"%#",imgLink];
item.artist = [NSString alloc]initWithFormat#"%#",artist];
Only based on this, it will create a leak, so you should be careful. To fix this:
item.name = [[NSString alloc]initWithFormat#"%#",name] autorelease];
item.imgUrl = [[NSString alloc]initWithFormat#"%#",imgLink] autorelease];
item.artist = [[NSString alloc]initWithFormat#"%#",artist] autorelease];
If you don't have ARC enabled than your destructor is correct. You are releasing all the properties that are retained and calling super, which is all you need.

Can't write in a .plist

I have a little app that have by default youtube as homepage. You can change it in a little menu, but it doesn't work and I don't know why.
Here's the code
viewController
.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
IBOutlet UIWebView *webView;
}
#property (retain, nonatomic) NSArray *array;
#property (retain, nonatomic) NSString *string1;
-(NSString *) dataFilePath;
- (IBAction)settings:(id)sender;
- (IBAction)home:(id)sender;
#end
.m
#import "ViewController.h"
#import "settings.h"
#implementation ViewController
#synthesize array;
#synthesize string1;
- (void)viewDidLoad
{
[super viewDidLoad];
if ([string1 isEqual:#"youtube"]) {
NSMutableArray *Array = [[NSMutableArray alloc] init];
[Array addObject:#"http://www.youtube.com"];
[Array writeToFile:[self dataFilePath] atomically:YES];
}
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
array = [[NSArray alloc] initWithContentsOfFile:filePath];
}
NSString *string = [NSString stringWithString:[array objectAtIndex:0]];
[webView loadRequest:[[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:string]]];
}
-(NSString *) dataFilePath
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"url.plist"];
string1 = #"youtube";
}
- (IBAction)settings:(id)sender {
settings *NView = [[settings alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:NView animated:YES];
}
- (IBAction)home:(id)sender {
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
array = [[NSArray alloc] initWithContentsOfFile:filePath];
}
NSString *string = [NSString stringWithString:[array objectAtIndex:0]];
NSLog(#"%#\n",string);
[webView loadRequest:[[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:string]]];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
Settings //here's the menu where I can change the homepage
.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface settings : UIViewController{
ViewController *viewCont;
IBOutlet UITextField *field;
}
-(IBAction)back:(id)sender;
- (IBAction)setHP:(id)sender;
#end
.m
#import "settings.h"
#import "ViewController.h"
#implementation settings
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib
}
- (void)viewDidUnload
{
field = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(IBAction)back:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)setHP:(id)sender {
NSMutableArray *Array = [[NSMutableArray alloc] init];
[Array addObject:field.text];
[Array writeToFile:[viewCont dataFilePath] atomically:YES];
[viewCont.string1 initWithString:#"other" ];
NSLog(#"%#\n", viewCont.string1);// HERE XCODE SAYS string1 = null!!! WHY?
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
So anyone knows what am I doing wrong? Please help me, I have searched around the web for 4 days and I didn't find anything!
I don't understand well your problem but i notice that you are not initializing viewCont in the setHP: action.
try to add this line:
ViewController *viewCont=[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
just before
[viewCont.string1 initWithString:#"other" ];

I am unable to copy my NSMutable array to appDelegate_iPhone array(Universal app)

Actually I have parsed an XML and store URL's of images as an NSMutableArray object, but I want this array to be used in another ViewController (to give to UIImage in UIImageView to show Images at runtime), so I am trying to copy that Mutable array to myAppDelegate_iPhone's NSMutableArray. And I want to again copy that Appdelegate's array to my next or other ViewControllers NSMutableArray.
so can anyone help me out pleaseeeeee? Here is my code :-
code:-
#class FirstViewController;
#interface AppDelegate_iPhone : NSObject <UIApplicationDelegate> {
UIWindow *window;
FirstViewController *viewController;
NSMutableArray *logoArray;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) NSMutableArray *logoArray;
#end
#import "AppDelegate_iPhone.h"
#import "FirstViewController.h"
#import "ParsingViewController.h"
#implementation AppDelegate_iPhone
#synthesize window,logoArray;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
viewController = [[FirstViewController alloc]initWithNibName:#"FirstViewController" bundle:nil];
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
NSURL *url = [[NSURL alloc] initWithString:#"http://litofinter.es.milfoil.arvixe.com/displayxml1.aspx"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
ParsingViewController *parser = [[ParsingViewController alloc] init];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
logoArray = [[NSMutableArray alloc]init];
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
// dealloc done
#end
#class Litofinter,AppDelegate_iPhone;
#interface ParsingViewController : NSObject<NSXMLParserDelegate> {
NSString *myString;
NSMutableArray *myMutableArray;
Litofinter *obj;
NSString *currentElement;
AppDelegate_iPhone *appDelegate;
}
#import "ParsingViewController.h"
#import "Litofinter.h"
#import "AppDelegate_iPhone.h"
#implementation ParsingViewController
#synthesize myMutableArray, myString;
-(id)init{
if(self == [super init]){
myMutableArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
//myMutableArray = [[NSMutableArray alloc]init];
}
// Parsing done here
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
//UIApplication *app = [UIApplication sharedApplication];
//appDelegate=app.delegate;
appDelegate.logoArray = [[NSMutableArray alloc]initWithArray:myMutableArray];
NSLog(#"appDelegate.logoArray count %d",[appDelegate.logoArray count]);
for (Litofinter *lito in appDelegate.logoArray) {
NSLog(#"Array Elements :----- %#",lito.cLogo);
}
}
#end
#import <UIKit/UIKit.h>
#class AppDelegate_iPhone,Litofinter,ParsingViewController;
#interface FirstViewController : UIViewController {
NSMutableArray *array;
//Litofinter *lito;
NSString *logoString;
AppDelegate_iPhone *appDelegate;
ParsingViewController *obj;
}
#end
#import "FirstViewController.h"
#import "AppDelegate_iPhone.h"
#import "Litofinter.h"
#import "ParsingViewController.h"
#implementation FirstViewController
-(id)init{
if(self == [super init]){
obj = [[ParsingViewController alloc] init];
array = [[NSArray alloc] initWithArray: obj.myMutableArray];
}
return self;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
int x=5,y=10;
appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
// UIApplication *app = [UIApplication sharedApplication];
// appDelegate=app.delegate;
NSLog(#"delegate Array ====== %d",[appDelegate.logoArray count]);
NSLog(#"New Array ====== %d",[obj.myMutableArray count]);
/*
array = [[NSMutableArray alloc]initWithArray:appDelegate.logoArray];
NSLog(#"array at 0 ===== %#",[array objectAtIndex:0]);
for (Litofinter *lito1 in obj.myMutableArray) {
NSLog(#"Array Elements in Lito1 are :------------- %#",lito1.cLogo);
}
for (Litofinter *lito2 in array) {
NSLog(#"Array Elements in Lito1 are :------------- %#",lito2.cLogo);
}
*/
for (Litofinter *lito in obj.myMutableArray) {
//for (int i=0; i<[appDelegate.logoArray count]; i++) {
// lito.cLogo = [array objectAtIndex:i];
NSLog(#"%#",lito.cLogo);
UIImage *imageFromUrl = [UIImage imageWithContentsOfFile:[NSURL fileURLWithPath:lito.cLogo]];
UIImageView *imgView = [[UIImageView alloc] initWithImage:imageFromUrl];
[imgView setFrame:CGRectMake(x, y, 196, 90)];
[self.view addSubview:imgView];
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onTapImage)];
[imgView addGestureRecognizer:tgr];
// [tgr release];
//Do the rest of your operations here, don't forget to release the UIImageView
x = x + 200;
}
}
-(void)onTapImage
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Message from mAc" message:#"Trail" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok",nil];
[alert show];
}
- (void)dealloc {
[super dealloc];
}
#end
You can use this.
UIImage *imageFromUrl = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:lito.cLogo]]];

Passing a Value Through a Navigation Controller

I'm looking to pass a user chosen value from one view to the next so it can be submitted to Twitter, Facebook, etc.
Would a global variable be best to implement? I don't want the value to be stored or saved anywhere.. just to make it through the end of the navigation controller (submission to Facebook, Twitter, etc.)
Any suggestions? Thanks in advance.
Header File
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "ShareViewController.h"
#include "TwitterRushViewController.h"
#interface KindViewController : UIViewController <UIPickerViewDelegate, UIScrollViewDelegate, CLLocationManagerDelegate> {
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageControl;
BOOL pageControlIsChangingPage;
CLLocationManager *locationManager;
NSString *finalCoordinates;
NSString *finalChoice;
}
#property (nonatomic, retain) UIView *scrollView;
#property (nonatomic, retain) UIPageControl *pageControl;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (retain) NSString *finalCoordinates;
#property (nonatomic, copy) NSString *finalChoice;
-(IBAction)changePage:(id)sender;
-(IBAction)submitChoice:(id)sender;
-(void)setupPage;
#end
Implementation File
#import "KindViewController.h"
#import "JSON/JSON.h"
#implementation KindViewController
#synthesize scrollView;
#synthesize pageControl;
#synthesize locationManager;
#synthesize finalCoordinates;
#synthesize finalChoice;
#pragma mark -
#pragma mark UIView boilerplate
- (void)viewDidLoad {
[self setupPage];
[super viewDidLoad];
// Alert the User on Location Access
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
}
-(void)viewWillAppear:(BOOL)animated {
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *location = newLocation;
NSLog(#"Our current Latitude is %f", location.coordinate.latitude);
NSLog(#"Our current Longitude is %f", location.coordinate.longitude);
NSString *Coordinates = [[NSString alloc] initWithFormat: #"Longitude=%f&Latitude=%f", location.coordinate.longitude, location.coordinate.latitude ];
NSLog(#"Test: %#", Coordinates);
finalCoordinates = Coordinates;
[locationManager stopUpdatingLocation];
}
#pragma mark -
#pragma mark The Guts
- (void)setupPage {
scrollView.delegate = self;
[scrollView setCanCancelContentTouches:NO];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
NSUInteger nimages = 0;
CGFloat cx = 0;
for (; ; nimages++) {
NSString *imageName = [NSString stringWithFormat:#"choice%d.png", (nimages + 1)];
UIImage *image = [UIImage imageNamed:imageName];
if (image == nil) {
break;
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = image.size.height;
rect.size.width = image.size.width;
rect.origin.x = ((scrollView.frame.size.width - image.size.width) / 2) + cx;
rect.origin.y = ((scrollView.frame.size.height - image.size.height) / 2);
imageView.frame = rect;
[scrollView addSubview:imageView];
[imageView release];
cx += scrollView.frame.size.width;
}
self.pageControl.numberOfPages = nimages;
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
}
#pragma mark -
#pragma mark UIScrollViewDelegate stuff
- (void)scrollViewDidScroll:(UIScrollView *)_scrollView {
if (pageControlIsChangingPage) {
return;
}
CGFloat pageWidth = _scrollView.frame.size.width;
int page = floor((_scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)_scrollView {
pageControlIsChangingPage = NO;
}
#pragma mark -
#pragma mark PageControl stuff
- (IBAction)changePage:(id)sender {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlIsChangingPage = YES;
}
-(IBAction)submitChoice:(id)sender; {
// Spinner
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(135,140,50,50)];
[spinner startAnimating];
[self.view addSubview:spinner];
// Find the Date
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"MMM dd, yyyy HH:mm"];
NSDate *now = [[NSDate alloc] init];
NSString *dateString = [format stringFromDate:now];
// Echo Everything
NSLog(#"Type is %f.", scrollView.contentOffset.x);
NSLog(#"Date is %#", dateString);
NSLog(#"Coordinates are %#", finalCoordinates);
NSString *completeURL = [[NSString alloc] initWithFormat: #"http://www.example.com/insert.php?Type=%f&Time=%#&%#", scrollView.contentOffset.x, dateString, finalCoordinates];
NSString *escapedUrl = [completeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"URL is %#.", escapedUrl);
// Post to Web Server
NSURL *urlToSend = [[NSURL alloc] initWithString:escapedUrl];
NSLog(#"NSURL is %#.", urlToSend);
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:urlToSend cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
NSData *urlData;
NSURLResponse *response;
NSError *error;
urlData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
// Do the Button Action
ShareViewController *shareViewController = [[ShareViewController alloc] initWithNibName:#"ShareViewController" bundle:nil];
shareViewController.finalChoice = #"Facebook Property";
[self.navigationController pushViewController:shareViewController animated:YES];
[shareViewController release];
[urlToSend release];
[completeURL release];
[spinner release];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"There is an error updating the location");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
[pageControl release];
}
- (void)dealloc {
[super dealloc];
}
#end
ShareViewController.h
#import <UIKit/UIKit.h>
#import "MapViewController.h"
#import "SA_OAuthTwitterController.h"
#import "FBConnect/FBConnect.h"
#import "TwitterRushViewController.h"
#import "oAuth2TestViewController.h"
#class SA_OAuthTwitterEngine;
#interface ShareViewController : UIViewController <UITextFieldDelegate, SA_OAuthTwitterControllerDelegate> {
}
#property (nonatomic, retain) IBOutlet UIButton *shareFacebookBTN;
#property (nonatomic, retain) IBOutlet UIButton *shareTwitterBTN;
#property (nonatomic, retain) KindViewController finalChoice;
/* Submissions */
- (IBAction)shareNoThanks:(id)sender;
- (IBAction)shareFacebook:(id)sender;
- (IBAction)shareTwitter:(id)sender;
#end
Just setting a property on the next UIViewController when you push it would probably be the easiest thing to do.
SomeViewController *someViewController = [[SomeViewController alloc] init];
someViewController.facebookProperty = #"Facebook Property";
someViewController.twitterProperty = #"Twitter Property";
[self.navigationController pushViewController:someViewController animated:YES];
[someViewController release];
Ok there are a few things wrong with ShareViewController.h. First if you have a property you also need to have an instance variable for that property. Next you are assigning a string to finalChoice but you have declared its type as KindViewController it should be NSString.
In ShareViewController.h
#interface ShareViewController : UIViewController <UITextFieldDelegate, SA_OAuthTwitterControllerDelegate> {
NSString *finalChoice;
}
#property (nonatomic, retain) IBOutlet UIButton *shareFacebookBTN;
#property (nonatomic, retain) IBOutlet UIButton *shareTwitterBTN;
#property (nonatomic, copy) NSString *finalChoice;
And make sure you #synthesize finalChoice in your implementation file.
Without knowing any of the specifics, I would avoid a global variable or tightly coupling the two views together.
Depending on your needs and implementation, delegation or notifications may a better choice to pass a variable between views.
There's a good discussion on the more general problem of how best to communicate between view controllers over here. The top-voted answer is pretty good.
The tl;dr version is basically:
Global variables and singleton classes are rarely the right answer.
Read up on the "dependency injection" design pattern.
Hope that helps.

UITableView custom class huge leak

I am using a custom class to display some info on a table view.
The problem is that as long as I scroll the tableview memory is leaking...
I guess I have something wrong at my class.
Please have a look:
#interface Person : NSObject {
NSString *name;
NSString *surname;
NSString *address;
NSString *email;
}
#property (nonatomic, copy) NSString *name, *surname, *address, *email;
#implementation Person
#synthesize name, surname, address, email;
-(id)init {
[super init];
name = [[NSString alloc] init];
surname = [[NSString alloc] init];
address = [[NSString alloc] init];
email = [[NSString alloc] init];
return self;
}
- (void)dealloc
{
[name release];
[surname release];
[address release];
[email release];
[super dealloc];
}
#import "Person.h"
#interface Group : NSObject {
NSString *groupTitle;
NSMutableArray *persons;
}
#property (readwrite, copy) NSString *groupTitle;
- (void)addPerson:(Person *)person;
- (void)removeAll;
- (NSArray *)getPersons;
- (int)PersonsCount;
#end
#implementation Group
#synthesize groupTitle;
-(id)init {
[super init];
persons = [[NSMutableArray alloc] init];
return self;
}
-(void)addPerson:(Person *)person {
[persons addObject:person];
}
-(void)removeAll {
[persons removeAllObjects];
}
-(NSArray *) getPersons {
return [persons copy];
[persons release];
}
-(int)personsCount {
return [persons count];
}
-(void)dealloc {
[groupTitle release], groupTitle = nil;
[persons release], persons = nil;
[super dealloc];
}
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
…….
Group *groupForRow = [[Group alloc] init];
Person *personForRow = [[Person alloc] init];
personForRow = [[groupForRow getPersons] objectAtIndex:indexPath.row];
_personName = personForRow.name;
_personSurname = personForRow.surname;
_personAddress = personForRow.address;
_personEmail = personForRow.email;
[groupForRow release], groupForRow = nil;
[personForRow release], personForRow = nil;
…..
return cell
Few corrections (read the comments):
#interface Person : NSObject {
NSString *name;
NSString *surname;
NSString *address;
NSString *email;
}
// copy is OK for strings...
#property (nonatomic, copy) NSString *name, *surname, *address, *email;
#end
#implementation Person
#synthesize name, surname, address, email;
- (id)init {
if (self = [super init]) {
// There is no need to allocate the strings
// In addition, once you write 'name = [[NSStrin alloc] init];' you don't use the property.
// If you do want to use the property setter then you should write 'self.name = #"some string";'
}
return self;
}
- (void)dealloc {
[name release];
[surname release];
[address release];
[email release];
[super dealloc];
}
#end
#import "Person.h"
#interface Group : NSObject {
NSString *groupTitle;
NSMutableArray *persons;
}
// Any special reason for "readwrite" instead of "nonatomic"?
#property (readwrite, copy) NSString *groupTitle;
// This property is more important than the string:
#property (nonatomic, retain) NSMutableArray *persons;
- (void)addPerson:(Person *)person;
- (void)removeAll;
- (NSArray *)getPersons;
- (int)PersonsCount;
#end
#implementation Group
#synthesize groupTitle, persons;
- (id)init {
if (self = [super init]) {
// Use the autoreleased array instance ([NSMutableArray array]) and set it to the property setter that will retain the object:
self.persons = [NSMutableArray array];
}
return self;
}
- (void)addPerson:(Person *)person {
// I prefer using properties (the "self." in the beginning) instead of the members directly...
[self.persons addObject:person];
}
- (void)removeAll {
[self.persons removeAllObjects];
}
// I think that this getter is unnecessary - use the property instead...
- (NSArray *) getPersons {
// There is no need to copy
return [persons copy];
// Don't you have a warning for this line? It is never executed
[persons release];
}
- (int)personsCount {
return [self.persons count];
}
- (void)dealloc {
[groupTitle release], groupTitle = nil;// The "groupTitle = nil" is unnecessary.
[persons release], persons = nil;// The "persons = nil" is unnecessary.
[super dealloc];
}
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
…….
Group *groupForRow = [[Group alloc] init];// Do you REALLY have to allocate this object each "cellForRowAtIndexPath"??
Person *personForRow = [[Person alloc] init];// Get rid of the "= [[Person alloc] init]" - this is a leak (because of the next line)
personForRow = [[groupForRow getPersons] objectAtIndex:indexPath.row];// If you will use the property persons instead of the "getPersons" (that copies the array) then you will get rid of another leak
// What are these?
_personName = personForRow.name;
_personSurname = personForRow.surname;
_personAddress = personForRow.address;
_personEmail = personForRow.email;
// The " = nil" is unnecessary here...
[groupForRow release], groupForRow = nil;// If you won't allocate the group then you won't need this line...
[personForRow release], personForRow = nil;// NSZombie - you release object that you don't owe (do you have crashes, that you don't know why they are happen?)
…..
return cell;
}
There is a lot wrong here, please delve a little into objective-C to get a grasp of the use of #property and #synthesize to get correctly functioning getter/setter methods.
As for your memory leak when scrolling, it is caused by the allocs in cellForRowAtIndexPath which are not balanced by either a release or an autorelease.
This:
Group *groupForRow = [[[Group alloc] init] autorelease];
Person *personForRow = [[[Person alloc] init] autorelease];
should fix most of your leaks. Browse around on SO for more info.