in my iOS app's viewDidLoad method, i have the following line of code:
loadDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"1.0", "version number", nil];
and it causes an EXC_BAD_ACCESS error. i don't know why. nothing else in the viewDidLoad method uses the object except the other side of the if/else statement this line is in, so there's no way it could have been released already. i'm just not sure what the problem is. if you want to see my whole viewDidLoad method, here it is:
- (void)viewDidLoad
{
[super viewDidLoad];
tapsBackground = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
tapsBackground.delegate = self;
[self.view addGestureRecognizer:tapsBackground];
saveChangesButton.hidden = YES;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [documentsDirectory stringByAppendingPathComponent:#"presets.plist"];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
loadDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
}
else{
loadDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"1.0", "version number", nil];
[loadDict writeToFile:filePath atomically:YES];
}
}
The problem is that you are missing # in the second string i.e. "version number".
loadDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"1.0", "version number", nil];
It should be,
loadDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"1.0", #"version number", nil];
I've faced the same issue once. Try this, it worked for me:
self.loadDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"1.0", "version number", nil];
I'm assuming you have already made loadDict a property. You can use Product>Profile>allocations to pin-point the problem in such cases.
Related
This is for my iCarouselViewController.m
- (void)dealloc
{
//it's a good idea to set these to nil here to avoid
//sending messages to a deallocated viewcontroller
carousel1.delegate = nil;
carousel1.dataSource = nil;
carousel2.delegate = nil;
carousel2.dataSource = nil;
[carousel1 release];
[carousel2 release];
[items1 release];
[items2 release];
[super dealloc];
}
I am getting an error saying
'release' is unavailable: not available in automatic reference
counting mode ARC forbids explicit message send of 'release'
'release' is unavailable: not available in automatic reference
counting mode ARC forbids explicit message send of 'release'
'release' is unavailable: not available in automatic reference
counting mode ARC forbids explicit message send of 'release'
'release' is unavailable: not available in automatic reference
counting mode ARC forbids explicit message send of 'release'
ARC forbids explicit message send of 'dealloc'
and error in this code aswell
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
UILabel *label = nil;
//create new view if no view is available for recycling
if (view == nil)
{
view = [[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)] autorelease];
((UIImageView *)view).image = [UIImage imageNamed:#"page.png"];
view.contentMode = UIViewContentModeCenter;
label = [[[UILabel alloc] initWithFrame:view.bounds] autorelease];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = UITextAlignmentCenter;
label.font = [label.font fontWithSize:50];
[view addSubview:label];
}
else
{
label = [[view subviews] lastObject];
}
saying
'autorelease' is unavailable: not available in automatic reference
counting mode ARC forbids explicit message send of
'autorelease' 'autorelease' is unavailable: not available in
automatic reference counting mode ARC forbids explicit message
send of 'autorelease'
How can I clear this error.
Update
Thank you for the answer I just have 4 error saying use of undeclared identifier imageArray1. and I know that this is happening. I just don't get " I assume you are just using app's bundle and we have two arrays of NSString which refer to each image: imageArray1 and imageArray2." Below is one of my save code and creating directory for one of my directories. Note: I have only one NSMutableArray called allImagesArray which I have declared in the header file.
NSArray *directoryNames = [NSArray arrayWithObjects:#"Apple",nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
for (int i = 0; i < [directoryNames count] ; i++) {
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:[directoryNames objectAtIndex:i]];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:nil]; //Create folder
NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:#"Tops"]; NSData *imageData = UIImagePNGRepresentation(captureImage.image);
time_t unixtime = (time_t)[[NSDate date]timeIntervalSince1970];
NSString *timestamp = [NSString stringWithFormat:#"%ldTopsImage.PNG",unixtime];
NSString *filePath = [folderPath stringByAppendingPathComponent:timestamp];
[imageData writeToFile:filePath atomically:YES];
}
}
Update 4
ThiS?
- (void)viewDidLoad
{
[super viewDidLoad];
//configure carousel
imageArray1 = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *location=#"apple";
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location];
NSArray * directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
imageArray1 = directoryContent;
imageArray2 = [[NSMutableArray alloc] init];
NSString *location=#"green";
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location];
NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
imageArray2 = directoryContent;
This is not an iCarousel issue. You are using statements like release, autorelease in your code. Remove it. In ARC you do not need to do memory management manually. That is why ARC is there.
UPDATE:
According to your comments, you are facing problems in displaying images for Mutiple Carousels.
I assume you are using two iCarousel objects. lets name them carousel1 and carousel2.
Also, it seems you are using sandbox for saving images. If this is the case, then you have to fetch images from your sandbox using NSFileManager. You need to keep looking at how to do that, but the code for iCarousel will remain more or less same in that case as well. Here, for simplicity case I assume you are just using app's bundle and we have two arrays of NSString which refer to each image: imageArray1 and imageArray2.
In viewDidLoad, set delegate and datasource objects of each carousel as self
carousel1.delegate = self;
carousel1.dataSource = self;
carousel2.delegate = self
carousel2.dataSource = self;
Implement datasource methods accordingly:
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
//return the total number of items in the carousel
if (carousel == carousel1)
{
return [imageArray1 count];
}
else
{
return [imageArray2 count];
}
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
UILabel *label = nil;
//create new view if no view is available for recycling
if (view == nil)
{
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)];
UIImage *image;
if (carousel == carousel1)
{
image = [UIImage imageWithContentsOfFile:[imageArray1 objectAtIndex:index]];
((UIImageView *)view).image = image;
}
else
{
image = [UIImage imageWithContentsOfFile:[imageArray2 objectAtIndex:index]];
((UIImageView *)view).image = image;
}
}
return view;
}
Well it is actually really easy, you have ticked the "Use Automatic Reference Counting" (ARC) box when creating your XCode project. To solve it just go to your target, (iCarousel I assume) and do this "buldsettings" ---> objective-c automaticrefcount :NO
The compiler should then work. What ARC does is do this stuff automatically for you, so you don't have to write auto release and release statements, but if you need them do what I suggested. Otherwise remove these release and autorelease statements.
That is because you're using ARC in your project and the code you showed here doesn't. To disable it in those classes add -fno-objc-arc. You can do so by going into the targets Build Phases tab. In Compile Sources group, double-click the file (class) and add the -fno-objc-arc flag.
Or you could just remove all release messages.
There are memory leaks in the below self.listOfCustDetail and self.listOfCustomer
-(void) calCustList {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistPath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"customer.plist"];
self.listOfCustDetail = [[[NSMutableArray alloc] init] autorelease];
self.listOfCustomer = [[[NSMutableArray alloc] init] autorelease];
self.customers = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistPath] autorelease];
[self.listOfCustomer removeAllObjects];
[self.listOfCustDetail removeAllObjects];
[self.listOfCustomer addObject:#"新紀錄"];
[self.listOfCustDetail addObject:#""];
for (id key in self.customers) {
NSString *s = [NSString stringWithFormat:#"%#,%#,%#,%#", [[self.customers objectForKey:key] objectAtIndex:0], [[self.customers objectForKey:key] objectAtIndex:1], [[self.customers objectForKey:key] objectAtIndex:2], [[self.customers objectForKey:key] objectAtIndex:3]];
[self.listOfCustomer addObject:key];
[self.listOfCustDetail addObject:s];
}
}
How are your properties definied? do they retain? If they do retain, there is no actual mistake in the piece of code, that you are showing.
How often is that method called? If it is called very often you could use a custom NSAutoreleasePool.
Also the following two lines are not needed on a newly initalized array:
[self.listOfCustomer removeAllObjects];
[self.listOfCustDetail removeAllObjects];
Are you showing the actual sourcecode?
I would like to suggest,enable ARC(auto reference counting) in Project because you no need To release arrays
I am building an app using storyboard. I have a view controller where the user has a set of tools (UILabels, images...), and can add these items by clicking on a specific button. When I exit the view controller or closes the app though all the data is lost. so I tried setting up a save button in this way:
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *cameraButton = [[UIBarButtonItem alloc]
initWithTitle:#"Camera"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(useCamera:)];
UIBarButtonItem *cameraRollButton = [[UIBarButtonItem alloc]
initWithTitle:#"Camera Roll"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(useCameraRoll:)];
NSArray *items = [NSArray arrayWithObjects: cameraButton,
cameraRollButton, nil];
[toolbar setItems:items animated:NO];
mouseMoved = 0;
array = [[NSMutableArray alloc]init];
array2 = [[NSMutableArray alloc]init];
array3 = [[NSMutableArray alloc]init];
NSFileManager *filemgr; NSString *docsDir; NSArray *dirPaths;
filemgr = [NSFileManager defaultManager];
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the data file
dataFilePath = [[NSString alloc] initWithString: [docsDir
stringByAppendingPathComponent: #"data.archive"]];
// Check if the file already exists
if ([filemgr fileExistsAtPath: dataFilePath]) {
dataArray = [NSKeyedUnarchiver unarchiveObjectWithFile: dataFilePath];
array = [dataArray objectAtIndex:0]; array2 = [dataArray objectAtIndex:1]; array3 = [dataArray objectAtIndex:2];
}}
-(void)saveData{
NSMutableArray *contactArray;
contactArray = [[NSMutableArray alloc] init]; [contactArray addObjectsFromArray:array]; [contactArray addObjectsFromArray:array2]; [contactArray addObjectsFromArray:array3]; [NSKeyedArchiver archiveRootObject:
contactArray toFile:dataFilePath];
[self.view addSubview: image1];
[self.view addSubview: text1];
[self.view addSubview: label1];
}
when I press the buttons the you can see that the codes are triggers (NSLog), but nothing happens. in the above example when I click save, the UILabel the user has created (alloc), should be saved, and when the app is open again, the button unarchive should place the label exactly how it is, and in the same position. I have to do tho even for the UIImageViews, and UITextFields.
Since I added all the user created labels... in an array, I want to save the whole objects in the array. The above code does not work though. I can't understand why.this is how I created the array and the object (in .h I added NSMutableArray *array;)
CGRect labelFrame = CGRectMake( 400, 100, 100, 30);
label1 = [[UILabel alloc] initWithFrame: labelFrame];
[label1 setText: #"Untitled"];
[label1 setTextColor: [UIColor orangeColor]];
[self.view addSubview:label1];
label1.backgroundColor = [UIColor clearColor];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scalePiece:)];
[label1 addGestureRecognizer:pinchGesture];
if (array == nil) array = [[NSMutableArray alloc]init];
[array addObject:label1];
thanks in advance for the help!!
Try logging your loaded objects and you should see that they are actually loaded. You don't see them of course since you don't add them to the view hierarchy. Try adding those lines after you get your objects from the dictionary:
[self.view addSubview: label1];
[self.view addSubview: text1];
[self.view addSubview: image1];
This might work, but it is not a good idea though. You really should read some introductory material to object-oriented programming and the Model/View/Controller (MVC) design pattern.
What I want to do is to populate a pickerView from an array based on a .plist, which can be added to from a textField. I've got it to work, but it only adds one key and replaces it when a new one is added. For instance if I add "hello", and then try to add another one, it replaces hello with something else.
- (IBAction)setContext:(id)sender {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [[NSBundle mainBundle] pathForResource:#"fullArray" ofType:#"plist"];
NSString *textFieldText = textField.text;
NSMutableDictionary *rootDict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
[rootDict setValue:textField.text forKey:textField.text];
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:#"fullArray.plist"];
[rootDict writeToFile:writablePath atomically: YES];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"fullArray.plist"]; //3
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
NSArray *array = [dictionary allKeys];
arrayContext = [[NSMutableArray alloc] initWithArray:array];
[pickerView selectRow:0 inComponent:0 animated:YES];
[textField endEditing:YES];
[pickerView reloadAllComponents];
}
How can I fix this?
Ok, you are creating a new NSMutableDictionary every time you pick something in the picker, the correct approach is:
Create a NSMutableDictionary as a property.
Every time you pick, create a new string for the key, maybe using [NSString stringWithFormat:].
use [mutableDictionary setObject:forKey] for set a new object in the mutant dictionary, with the new created key.
UPDATE: Figured out some stuff and changed code.
When I add my NSDictionary to my array it suddenly replaces the previous dictionary I added last time. I don't know why this is happening. I am using a plist as data storage.
I get a error message like this:
Thread 1:Program received signal: "EXC_BAD_ACCESS".
Init
-(id)init{
self=[super init];
if(self){
dbArray = [[NSMutableArray alloc] init];
}
return self;
}
Adding a new item.
-(void)addNewItem:(NSString *)aString
{
// Creates a mutable dictionary with a anonymous string under the NAME key.
NSDictionary *newString = [[NSDictionary alloc] initWithObjectsAndKeys:aString,#"name", nil];
// Adds the new string to empty dbArray.
[dbArray addObject:(newString)];
NSLog(#"[add]:Added anonymous string to dbArray, under name key.");
// Writes the current dbArray (with the dict) to plist and releases retain counts.
[self writeItem];
[newString release];
}
My method to view my data.
-(void)viewData
{
// View data from the created plist file in the Documents directory.
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *finalPath = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:finalPath]) {
self.dbArray = [NSMutableArray arrayWithContentsOfFile:finalPath];
}
else {
self.dbArray = [NSMutableArray array];
}
}
instead this
self.dbArray = [[NSMutableArray alloc] init];
use this
if( nil == self.dbArray ) {
self.dbArray = [[NSMutableArray alloc] init];
}
UPDATE: (based on provided code)
you're using different instances of DataObject class for displaying & saving data. Your content is over-written, because you don't load data from file during initialization of each instance; to fix that fast, you need to implement init method of your DataObject class as below:
- (id)init{
self = [super init];
if(self){
[self viewData];
}
return self;
}
the following code from viewDidLoad of ViewController class will crash your application very often:
db = [[DataObject alloc] init];
[db viewData];
[db release];
array = [[NSMutableArray alloc] initWithArray:[db dbArray]];
replace it with
db = [[DataObject alloc] init];
[db viewData];
array = [[NSMutableArray alloc] initWithArray:[db dbArray]];
call [db release] only in dealloc implementation
another problem, that you'll probably arise - is updated data is not displayed when you're back to the main screen; to fix that add the following method implementation to your ViewController.m file:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[db viewData];
self.array = [NSMutableArray arrayWithArray: db.dbArray];
[self.tableView reloadData];
}
also in AddView.m replace the following code
// Dismiss view and reload tableview.
ViewController *vc = [[ViewController alloc] init];
[self dismissModalViewControllerAnimated:YES];
[vc release];
with
// Dismiss view and reload tableview.
[self dismissModalViewControllerAnimated:YES];
Just as advise: see more information about using delegates and passing object instances & copies between objects.
I think you are creating a new Array:
self.dbArray = [[NSMutableArray alloc] init];
You should create the dbArray on the viewDidLoad or on the init of your UIViewController (I am assuming you are using this on an UIViewController)
inside your DataObject do the following:
-(id)init{
self=[super init];
if(self){
self.dbArray = [[NSMutableArray alloc] init];
}
return self;
}