accessing class file crashes when scrolling starts (UIScrollview) - iphone

hopefully someone will be able to help me. I have a UIScrollView on my page. The .h file has set the UIscrollviewdelegate.
I have a class file called "Picture.h / Picture.m".
- (id)initWithName:(NSString *)aName filename:(NSString *)aFilename {
self.name = aName;
self.filename = aFilename;
return self;
}
In this class file, I simply set a couple of strings. I load an array with object of this picture class, for example
Picture *image2 = [[Picture alloc] initWithName:#"Apple" filename:#"apple.png"];
[pictureArray addObject: image2];
[image2 release];
Within my viewController, I call this class and assign is as such
Picture *thisPicture = (Picture *)[appDelegate.pictureArray objectAtIndex:0];
view2image.image = [UIImage imageNamed:[NSString stringWithFormat:#"%#", thisPicture.filename]];
The above works fine. The image is set to what ever I put, example, "apple.png". However, when I tried to set this in the - (void) scrollViewDidScroll:(UIScrollView *) method within my viewController, I get a bad exec error and the app crashes.
Yet, if I had an array of filenames (so not storing my class object in the array) and access objectAtIndex:0 in the scrollViewDidScroll - it works fine.
So, this code is OK
nextImageView.image = [UIImage imageNamed: [NSString stringWithFormat:#"%#", [appDelegate.pictureCardsArray objectAtIndex:0]]];
but this crashes
Picture *image3 = (Picture *)[appDelegate.pictureArray objectAtIndex:0];
nextImageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"%#", image3.filename]];
Interestingly though, if I don't try to access the element of image3 (eg image3.filename) it doesn't crash. This is useless though! Also, if I disable the delegate = self for the uiscrollview, then this code works, but none of the scrolling actions are fired. I came across this post (http://stackoverflow.com/questions/1734720/uiscrollview-on-a-uiviewcontroller) when searching for the solution, but cannot see where I might be releasing the viewController early. To be safe, nothing is getting released (yet!)
Hopefully someone might be able to shed some light on it!!
[edit]Just adding in the full class files][/edit]
Picture.h
#import <UIKit/UIKit.h>
#interface Picture : NSObject {
NSString *name;
NSString *filename;
}
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *filename;
- (id)initWithName:(NSString *)aName filename:(NSString *)aFilename;
#end
Picture.m
#import "Picture.h"
#implementation Picture
#synthesize name, filename;
- (id)initWithName:(NSString *)aName filename:(NSString *)aFilename {
self.name = aName;
self.filename = aFilename;
return self;
}
#end

Just for completeness... the solution was as Antwen Van Houdt said - I changed copy to retain and it worked fine.
#import <UIKit/UIKit.h>
#interface Picture : NSObject {
NSString *name;
NSString *filename;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *filename;
- (id)initWithName:(NSString *)aName filename:(NSString *)aFilename;
#end

Related

add data to my data member

Hello I'm new to iPhone development.
I try to add move data from NSDictionary to data member of calls that i created.
When i "setWeightMeasure" nothing happened.
any suggestions?
the code that don't work:
NSDictionary *responseBodyProfile = [responseBody objectFromJSONString];
NSLog(#"%#",responseBodyProfile);
// the output is :
"{ "profile": {"goal_weight_kg": "77.0000", "height_cm": "179.00",
"height_measure": "Cm", "last_weight_date_int": "15452",
"last_weight_kg": "99.0000", "weight_measure": "Kg" }}""
[responseBody release];
if (responseBodyProfile != nil ){
NSDictionary *profile =[responseBodyProfile valueForKey:#"profile"];
NSLog(#"%#\n",[profile objectForKey:#"weight_measure"]);// Output : "kg"
[self.myUser setWeightMeasure:[profile objectForKey:#"weight_measure"]];
NSLog(#"%#", [self.myUser WeightMeasure]); // Output : "(null)"
}
the H file properyty:
#property (nonatomic, retain) UserData* myUser;
UserData.h:
#import <Foundation/Foundation.h>
#interface UserData : NSObject{
NSString* Weight;
NSString* Height;
NSString* GolWeight;
NSString* WeightMeasure;
}
#property (nonatomic, retain) NSString* Weight;
#property (nonatomic, retain) NSString* Height;
#property (nonatomic, retain) NSString* GolWeight;
#property (nonatomic, retain) NSString* WeightMeasure;
#end
UserData.m
#import "UserData.h"
#implementation UserData
#synthesize Weight, Height, GolWeight, WeightMeasure;
-(id)init{
self.Weight = #"0";
self.Height = #"0";
self.GolWeight = #"0";
self.WeightMeasure = #"0";
return self;
}
-(void)dealloc{
[Weight release];
[Height release];
[GolWeight release];
[WeightMeasure release];
[super dealloc];
}
#end
Use valueForKey instead of objectForKey in this line:
[self.myUser setWeightMeasure:[profile objectForKey:#"weight_measure"]];
like this:
[self.myUser setWeightMeasure:[profile valueForKey:#"weight_measure"]];
You might also want to use, since the values could be read as NSNumbers
[self.myUser setWeightMeasure:[[profile valueForKey:#"weight_measure"] stringValue]];
And why do you use strings instead of floats? Wouldn't that make your life easier when you'd need to perform some comparisons?
Also check if you have allocated memory for "myUser", that might be the case as well.
As Eugene mentioned, you should use valueForKey instead of objectForKey
The other thing is you might wanna use property and dot notation whenever you reference your object members, as Apple recommend. It is generally good for you to manage memory.
The previous answer about not initialize your string members in your -init() was totally wrong, if that cause some confusion, I do apologize for it.

Converting HTML to Plain Text for MapKit Annotations

I have a problem when I use an annotation to see information with MapKit.
I ran into a similar issue. You're not crazy. I believe it's a bug in the MapKit code. The Annotation object doesn't create it's own copy of the strings you pass to it. When your string goes out of scope, the map makes a bad reference. Try re-allocating the strings before you pass them. Like so:
NSString *tempT = [[NSString alloc] initWithString:itemT];
NSString *tempA = [[NSString alloc] initWithString:itemA];
addAnnotation = [[MapAnnotation alloc] initWithCoordinate:essai :tempT :tempA];
And then don't release them until you're finished displaying the map.
I ran into the exact same problem, as Jonesy mentioned, but there is a fix. I'm not sure what kind of class you have for your annotations, but I use this:
Annotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#interface LocationAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString* title;
NSString* subtitle;
}
#property (nonatomic, assign) MKPinAnnotationColor pinColor;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* subtitle;
- (id)initWithCoordinate:(CLLocationCoordinate2D) c
title:(NSString*) t
subtitle:(NSString*) st;
- (void)moveAnnotation:(CLLocationCoordinate2D) newCoordinate;
- (NSString*)subtitle;
- (NSString*)title;
#end
And Annotation.m:
#import "LocationAnnotation.h"
#implementation LocationAnnotation
#synthesize coordinate, pinColor, title, subtitle;
- (NSString *)subtitle {
return subtitle;
}
- (NSString *)title {
return title;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D) c
title:(NSString*)t
subtitle:(NSString*)st
{
coordinate = c;
self.title = t;
self.subtitle = st;
return self;
}
- (void)moveAnnotation:(CLLocationCoordinate2D)newCoordinate
{
coordinate = newCoordinate;
}
- (void)dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
#end
To implement it:
Annotation* ann = [[[Annotation alloc] initWithCoordinate:startLocation title:someStringAutoreleasedOrNot subtitle:someOtherStringAutoreleasedOrNot] autorelease];
[yourMapView addAnnotation:ann];
Really, the key here is that in the annotation class, the title and subtitle properties are declared as type copy. This makes a new copy of the string you assign it, so it can be released without causing the crash that you are having.
I dont see stringByStandardizingWhitespace method call in the above code you pasted... It would be helpful if you can post the code which has the error. Use debugger to know where the error is occuring...
Also one error which is not related to the syntax/error you specified but would effect the logic later:
you are assigning the gps_long tag tpo lat and vice versa ...

Unknown Memory Leak in iPhone

I am currently building an app for the iPhone and cannot figure out why I keep getting a memory leak to appear in the Leaks Instrument tool.
Here is the code and I have added comments to two places of where it is happening.
NSString *pathname = [[NSBundle mainBundle] pathForResource:self.toUseFile ofType:#"txt" inDirectory:#"/"];
//Line below causes a leak
self.rawCrayons = [[NSString stringWithContentsOfFile:pathname encoding:NSUTF8StringEncoding error:nil] componentsSeparatedByString:#"\n"];
self.sectionArray = [NSMutableArray array];
for (int i = 0; i < 26; i++) [self.sectionArray addObject:[NSMutableArray array]];
for(int i=0; i<self.rawCrayons.count; i++)
{
self.string = [self.rawCrayons objectAtIndex:i];
NSUInteger firstLetter = [ALPHA rangeOfString:[string substringToIndex:1]].location;
if (firstLetter != NSNotFound)
{
NSInteger audio = AUDIONUM(self.string);
NSInteger pictures = PICTURESNUM(self.string);
NSInteger videos = VIDEOSNUM(self.string);
//Line below causes a leak
[[self.sectionArray objectAtIndex:firstLetter] addObject:[[Term alloc] initToCall:NAME(self.string):audio:pictures:videos]];
}
[self.string release];
}
Thanks in advance!
Edit
Here are my property declarations.
#property (nonatomic, retain) NSArray *filteredArray;
#property (nonatomic, retain) NSMutableArray *sectionArray;
#property (nonatomic, retain) UISearchBar *searchBar;
#property (nonatomic, retain) UISearchDisplayController *searchDC;
#property (nonatomic, retain) NSString *toUseFile;
#property (nonatomic, retain) NSArray *rawCrayons;
#property (nonatomic, retain) NSString *string;
#property (nonatomic, retain) TermViewController *childController;
Here are the leaks that are occurring after follow Nick Weaver's fixes.
Here is an expanded version of one of the NSCFString.
And another image.
Image with the Responsible Caller:
Also, because this may be useful, here are the properties for Term:
#property (nonatomic, retain) NSString *name;
#property (nonatomic) NSInteger numberAudio;
#property (nonatomic) NSInteger numberPictures;
#property (nonatomic) NSInteger numberVideos;
And the implementation:
#implementation Term
#synthesize name, numberAudio, numberPictures, numberVideos;
- (Term*)initToCall:(NSString*) toSetName:(NSInteger) audio:(NSInteger) pictures:(NSInteger) videos
{
self.name = [toSetName retain];
self.numberAudio = audio;
self.numberPictures = pictures;
self.numberVideos = videos;
return self;
}
- (NSString*)getName
{
return [[name retain] autorelease];
}
-(void)dealloc
{
[name release];
[super dealloc];
}
#end
Ok, try this changed Version of Temp. I've deleted the getter because you have already one by synthesizing. You cann use the getter like this for name:
term.name
The problem was how you set the name: you want a copy of the name and setting it with the synthesized setter without calling a retain should do the trick. You could, of course, have set it with the retained property of name but you should have left out retain, like this self.name = toSetName;. The setter will retain it for you.
#property (nonatomic, copy) NSString *name;
#property (nonatomic) NSInteger numberAudio;
#property (nonatomic) NSInteger numberPictures;
#property (nonatomic) NSInteger numberVideos;
#implementation Term
#synthesize name, numberAudio, numberPictures, numberVideos;
- (Term*)initToCall:(NSString*) toSetName:(NSInteger) audio:(NSInteger) pictures:(NSInteger) videos
{
self.name = toSetName;
self.numberAudio = audio;
self.numberPictures = pictures;
self.numberVideos = videos;
return self;
}
-(void)dealloc
{
[name release];
[super dealloc];
}
Adding an object to an array will retain the instance, so the retain is 2 because you call
[[Term alloc] initToCall..
Do something like
Term *term = [[Term alloc] initToCall..];
[theArray addObject:term];
[term release];
1. See the arrow in the first line in the address column? Click it!
2. After clicking :)
Hard to tell you why the first one is leaking, because we don't know what the property is declared as. Is it retain? copy? assign? what?
The last one is fairly self explanatory though, you're taking ownership of a Term object, and not releasing it when it's added. addObject: retains its argument, meaning if you don't need that Term anymore, you need to give up ownership. I.e., pass -autorelease to the result of your initToCall:::: (which btw is a very bad name for a method)
Change:
[[self.sectionArray objectAtIndex:firstLetter] addObject:[[Term alloc] initToCall:NAME(self.string):audio:pictures:videos]];
to:
Term *tempTerm = [[Term alloc] initToCall:NAME(self.string):audio:pictures:videos];
[[self.sectionArray objectAtIndex:firstLetter] addObject:tempTerm];
[tempTerm release];
By alloc'ing an object you are responsible for it's release.

passing NSString from one class to the other

I have a NSString that is taken from a UITextField in a ViewController. Every of my other ViewController will use this NSString as well. How can I pass this NSString to others ViewControllers?
You want to have a property in each of your controllers
#interface MyViewController : UIViewController{
NSString *title;
}
#property (retain) NSString *title;
#end;
#implementation MyViewController
#synthesize title;
#end;
Use it like:
MyViewController *myVC = [[MyViewController alloc] initWithFrame:...];
myVC.title = #"hello world";
You should be familiar with Memory Management
Create a class for sharing your common objects. Retrieve it using a static method, then read and write to its properties.
#interface Store : NSObject {
NSString* myString;
}
#property (nonatomic, retain) NSString* myString;
+ (Store *) sharedStore;
#end
and
#implementation Store
#synthesize myString;
static Store *sharedStore = nil;
// Store* myStore = [Store sharedStore];
+ (Store *) sharedStore {
#synchronized(self){
if (sharedStore == nil){
sharedStore = [[self alloc] init];
}
}
return sharedStore;
}
// your init method if you need one
#end
in other words, write:
Store* myStore = [Store sharedStore];
myStore.myString = #"myValue";
and read (in another view controller):
Store* myStore = [Store sharedStore];
myTextField.text = myStore.myString;
If the string remains the same, and never changes, you could make a file named defines.h (without the .m file) and have this line:
#define kMyString #"Some text"
Then wherever you need the string, just import the defines file and use the constant.
#import "defines.h"
Much simpler than making custom classes.
EDIT:
Didn't see you needed to grab from the text field.
In that case, you could have it stored as property of your app delegate class and get it from there. The delegate can be accessed from anywhere in your app.

EXC_BAD_ACCESS when calling class init in Objective C

I've been trying to figure this out but I can't figure out what I'm doing wrong.
I wrote a class and whenever I try to initialize it, I get a EXC_BAD_ACCESS error. I can't even step into the initialization.
Anyone have any idea what I'm doing wrong?
User *myUser = [myUser init];
.h file:
#import <Foundation/Foundation.h>
#interface User : NSObject {
long rowId;
NSString *email;
NSString *password;
NSString *fileVersion;
}
#property long rowId;
#property (assign) NSString *email;
#property (assign) NSString *password;
#property (assign) NSString *fileVersion;
#end
.m file
#import "User.h"
#implementation User
#synthesize rowId, email, password, fileVersion;
-(id)init {
self = [super init];
return self;
}
#end
You have to actually allocate the object:
User *myUser = [[User alloc] init];
Don't forget to release it when you're done using it.