EXC_BAD_ACCESS iPhone Dev - objective-c

I am very new to development in Objective C but have a lot of experience in object orientated development in c# ASP. I've been trying to make a simple iPhone app where a PickerView control is accessing a data source.
In my header file (InstaTwitViewController.h) I have declared the following:
#interface InstaTwitViewController : UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate> {
NSArray* activities;
NSArray* feelings;
}
I now try to inititialise my arrays in the viewDidLoad functions in my InstaTwitViewController.m file:
activities = [[NSArray alloc] initWithObjects:#"sleeping", #"eating", #"thinking", nil];
feelings = [[NSArray alloc] initWithObjects:#"psyched", #"sad", #"happy", nil];
but when I run the code on the simulator I get a Thread 1: Program recieved signal "ESC_BAD_ACCESS" error on the first line of code (where I allocate data to the activities array).
I put a break point on the line and it recognises it as an NSArray called activities but says "Invalid Summary" at the end.
Does anyone know why I am getting this error? I have looked at many threads about the ESC_BAD_ACCESS error but none have seemed to have helped me.

.h
#interface InstaTwitViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate> {
NSArray* activities;
NSArray* feelings;
}
#property (nonatomic, retain) NSArray* activities;
#property (nonatomic, retain) NSArray* feelings;
#end
.m
#import "your.h"
#implementation InstaTwitViewController
#synthesize activities, feelings;
- (void)viewDidLoad {
[super viewDidLoad];
[self.activities addObject ~ /* Do your code here */];
}
#end
Becareful you should stay on self.~ if you don't want to lose your value.
By the way, I am Korean~ ^^;

Related

Instance method returns correct array from one view controller but null from others

This is my first post so apologies for any errors I make, but this has been frustrating me for hours now and I cannot find a solution.
I have an app that uses a UITabBarViewController that has 3 tabs: FirstViewController, SecondViewController and ThirdViewController.
I have an NSObject class (Manager) where I reach out to from my view controllers to pull information from the calendar. Which works perfectly fine when I use the FirstViewController, however, when I go to use the other view controllers it simply returns "null" but I know the instance method is being called because I put an NSLog in the instance method it returns a value, but this value isn't being passed onto view controllers two and three.
The code I am using is below.
AppDelegate.m
#import <UIKit/UIKit.h>
#import "EventManager.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
}
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) EventManager *eventManager;
#end
AppDelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application {
self.eventManager = [[EventManager alloc] init];
}
EventManager.h
#import <Foundation/Foundation.h>
#import <EventKit/EKEventStore.h>
#interface EventManager : NSObject
#property (nonatomic, strong) EKEventStore *eventStore;
-(NSMutableArray *) fetchCalendars;
#end
EventManager.m
-(NSMutableArray *) fetchCalendars {
NSArray *EKCalendars = [self.eventStore calendarsForEntityType:EKEntityTypeEvent];
NSMutableArray *mutableCalendars = [[NSMutableArray alloc] initWithArray:EKCalendars];
NSLog(#"EKCalendars %#",EKCalendars);
return mutableCalendars;
}
FirstViewController.m
-(void)loadCalendars{
NSMutableArray *mutableCalendars = [self.appDelegate.eventManager fetchCalendars];
}
This works absolutely fine for loading the calendars.
SecondViewController.m
-(void)loadCalendars{
NSMutableArray *mutableCalendars = [self.appDelegate.eventManager fetchCalendars];
}
This returns null, however, the output from the NSLog[ NSLog(#"EKCalendars %#",EKCalendars)] gives the exact same output as when it code is ran for the First View Controller.
I can get the calendars from the altering the SecondViewController.m to read
-(void)loadCalendars{
EventManager *per= [[EventManager alloc]init];
calendarsArray = [per fetchCalendars];
}
But I just don't understand why I need to reinitialize the event manager as it is initialized in the applicationDidBecomeActive.
Thanks for any help you guy can give.
You can access the Application's AppDelegate using [UIApplication sharedApplication].delegate:
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSMutableArray *mutableCalendars = [appDelegate.eventManager fetchCalendars];

How to initialize the NSArray in ARC?

I tried initializing the array :
In .h file
#property (nonatomic, retain) NSArray *accounts;
In .m file :
#synthesize accounts;
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *arrList = [acAccountStore accountsWithAccountType:accountType];
// This returns array
self.accounts = [NSArray arrayWithArray:arrList]; // I tried debug after
// this and it gives me data in debugger.
// Note array List have 3 data in it.
}
Now On button click i call a method:
- (IBAction) ButtonClicked :(id) sender {
NSLog(#" data : %#",[self.accounts objectAtIndex:0]); // Breaks at this point.
// When i tried with debug it gives me (no Objective-C description available)
}
Is the initialization of array correct Or If the code is not right please let me know.
Main concern is when i do debug in viewDidLoad, the self.accounts show me proper values. But after doing the click event its empty and throws EXEC_BAD_ACCESS error.
Thanks for help in advance
hm looks fine. A couple of questions then:
Where are you calling the self.accounts = [NSArray arrayWithArray:arrList];
I assume that the array is being setup before your button is being pressed?
There's no real reason that arc should be clearing out the variable. Have you set a strong reference to it or a weak one? If you're using self. on a variable, you should have :
#property (nonatomic, strong) NSArray *accounts;
or similar to that in the .h file and then
#synthesize accounts;
in the .m file.
If you've got weak instead of strong then ARC may possibly clear the memory but it still shouldn't.
Update:
Create a property for your account store as well. I had this exact issue recently and this fixed it.
#property (nonatomic, strong) ACAccountStore *accountStore;
Original Answer
Because you're using ARC, you need to change your property declaration from
#property (nonatomic, retain) NSArray *accounts;
to:
#property (nonatomic, strong) NSArray *accounts;
With the latest LLVM compiler, you don't need to synthesize properties either. So you can remove #synthesize accounts.
You should always use defensive coding as well, so in your - buttonClicked: method, you should do:
- (IBAction)buttonClicked:(id)sender {
if (self.accounts) {
NSLog(#"data: %#", [self.accounts objectAtIndex:0]);
}
}
This makes sure that the pointer to the array is valid.
You can also check to make sure an item in an array exists before trying to read it by doing:
- (IBAction)buttonClicked:(id)sender {
if (self.accounts.count > 0)
NSLog(#"data: %#", [self.accounts objectAtIndex:0]);
}
}

Crash on NSMutableDictionary's setObject function

Here is my code:
NSLog(#"dictionaryPlayers=%#,%d",[dictionaryPlayers description],dictionaryPlayers.count);
[dictionaryPlayers setObject:#"test" forKey:#"test2"];
dictionaryPlayers is inited in this class's init function:
-(id)init{
...
dictionaryPlayers = [[NSMutableDictionary dictionaryWithCapacity:10]retain];
...
}
The program crashed:
Thread 1:Program received signal: "SIGABRT".
And in console:
2011-12-27 17:01:21.744 [25454:207] dictionaryPlayers={
},0
2011-12-27 17:01:21.745 [25454:207] -[__NSCFConstantString tick]: unrecognized selector sent to instance 0x199bcc
With the NSLog outputs, i think dictionaryPlayers is well inited. So I don't know why crashed...
The object on which you call tick: is not longer in memory and causes this crash. Try to see why this object is released.
It seems that this is not a local case, so did you make sure to synthesize it at the top? And declared it correctly in the header? Examples:
In header:
#property (nonatomic, strong) NSMutableDictionary *dictionaryPlayers;
in class:
#synthesize dictionaryPlayers = _dictionaryPlayers;
I removed
dictionaryPlayers = [NSMutableDictionary dictionaryWithCapacity:10];
from init(), and added
dictionaryPlayers = [[NSMutableDictionary alloc] init];
above my log statement. Still crash....
Then I removed
[dicTest setValue:#"Test" forKey:#"testKey"];
So there's only 2 lines left:
dictionaryPlayers = [[NSMutableDictionary alloc] init];
NSLog(#"dictionaryPlayers=%#,%d",[dictionaryPlayers description],dictionaryPlayers.count);
It didn't crash. So, it seems the setValue line really is the problem.
You don't need to call retain on the object in your init statement. Also just for giggles try:
dictionaryPlayers = [[NSMutableDictionary alloc] init];
instead of
dictionaryPlayers = [NSMutableDictionary dictionaryWithCapacity:10];
And do this right above your log statement (take it out of the init).
If this works, put a log in your init method and make sure that is being called before your method that adds KV's to the dictionary
I cannot reproduce this behavior. Here is my code:
ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property(nonatomic, retain) NSMutableDictionary *dictionaryPlayers;
#property (retain, nonatomic) IBOutlet UITextView *logTextView;
- (IBAction)logButtonPressed:(id)sender;
#end
ViewController.m:
#import "ViewController.h"
#implementation ViewController
#synthesize dictionaryPlayers;
#synthesize logTextView;
#pragma mark - My Methods
- (IBAction)logButtonPressed:(id)sender {
logTextView.text = [NSString stringWithFormat:#"%#,%d",[dictionaryPlayers description],[dictionaryPlayers count]];
NSLog(#"dictionaryPlayers=%#,%d",[dictionaryPlayers description],[dictionaryPlayers count]);
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
dictionaryPlayers = [[NSMutableDictionary alloc] init];
[dictionaryPlayers setValue:#"Test" forKey:#"testKey"];
NSLog(#"dictionaryPlayers=%#,%d",[dictionaryPlayers description],[dictionaryPlayers count]);
}
No issues. If you are doing things this way, you cannot have problems. Here are the steps I would take to troubleshoot further:
Do a project search for playersDictionary and make sure there isn't something else touching that object.
Try cleaning the project
Create a new project with this structure and see what happens

Pass array from one Objective-C class to another

Im attempting to pass an array that is created in one class into another class. I can access the data but when I run count on it, it just tells me that I have 0 items inside the array.
This is where peopleArray's data is set up, it's in a different class than the code that is provided below.
[self setPeopleArray: mutableFetchResults];
for (NSString *existingItems in peopleArray) {
NSLog(#"Name : %#", [existingItems valueForKey:#"Name"]);
}
[peopleArray retain];
This is how I get the array from another class, but it always prints count = 0
int count = [[dataClass peopleArray] count];
NSLog(#"Number of items : %d", count);
The rest of my code:
data.h
#import <UIKit/UIKit.h>
#import "People.h"
#class rootViewController;
#interface data : UIView <UITextFieldDelegate>{
rootViewController *viewController;
UITextField *firstName;
UITextField *lastName;
UITextField *phone;
UIButton *saveButton;
NSMutableDictionary *savedData;
//Used for Core Data.
NSManagedObjectContext *managedObjectContext;
NSMutableArray *peopleArray;
}
#property (nonatomic, assign) rootViewController *viewController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSMutableArray *peopleArray;
- (id)initWithFrame:(CGRect)frame viewController:(rootViewController *)aController;
- (void)setUpTextFields;
- (void)saveAndReturn:(id)sender;
- (void)fetchRecords;
#end
data.m(some of it at least)
#implementation data
#synthesize viewController, managedObjectContext, peopleArray;
- (void)fetchRecords {
[self setupContext];
// Define our table/entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"People" inManagedObjectContext:managedObjectContext];
// Setup the fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
// Define how we will sort the records
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
// Fetch the records and handle an error
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults) {
// Handle the error.
// This is a serious error and should advise the user to restart the application
}
// Save our fetched data to an array
[self setPeopleArray: mutableFetchResults];
for (NSString *existingItems in peopleArray) {
NSLog(#"Name : %#", [existingItems valueForKey:#"Name"]);
}
[peopleArray retain];
[mutableFetchResults release];
[request release];
//NSLog(#"this is an array: %#", eventArray);
}
login.h
#import <UIKit/UIKit.h>
#import "data.h"
#class rootViewController, data;
#interface login : UIView <UITextFieldDelegate>{
rootViewController *viewController;
UIButton *loginButton;
UIButton *newUser;
UITextField *entry;
data *dataClass;
}
#property (nonatomic, assign) rootViewController *viewController;
#property (nonatomic, assign) data *dataClass;
- (id)initWithFrame:(CGRect)frame viewController:(rootViewController *)aController;
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField;
#end
login.m
#import "login.h"
#import "data.h"
#interface login (PrivateMethods)
- (void)setUpFromTheStart;
- (void)loadDataScreen;
-(void)login;
#end
#implementation login
#synthesize viewController, dataClass;
-(void)login{
int count = [[dataClass peopleArray] count];
NSLog(#"Number of items : %d", count);
}
Is it the same object? If so, what you have should work. Check to see how you are getting the dataClass instance -- if you alloc a new one, you don't get the array from the other object.
Edit: From your comments below, it appears that you are having some confusion on the difference between classes and objects. I will try to explain (I'm going to simplify it):
A class is what you write in Xcode. It's the description that lets your application know how to create and access objects at run-time. It is used to figure out how much memory to allocate (based on instance variables) and what messages can be sent, and what code to call when they are. Classes are the blueprints for creating objects at runtime.
An object only exists at run-time. For a single class, many objects of that class can be created. Each is assigned its own memory and they are distinct from each other. If you set a property in one object, other objects don't change. When you send a message to an object, only the one you send it to receives it -- not all objects of the same class.
There are exceptions to this -- for example if you create class properties (with a + instead of a - at the beginning), then they are shared between all objects -- there is only one created in memory, and they all refer to the same one.
Also, since everything declared with a * is a pointer -- you could arrange for all pointer properties to point to the same data. The pointer itself is not shared.
Edit (based on more code): dataClass is nil, [dataClass peopleArray] is therefore nil, and then so is the count message call. You can send messages to nil, and not crash, but you don't get anything useful.
I don't see how the login object is created. When it is, you need to set its dataClass property.
Try running the code in the debugger, setting breakpoints, and looking at variables.
From the code, it looks like you are passing a mutable array.
[self setPeopleArray: mutableFetchResults];
Probably the items of the array are removed somewhere in your calling class / method. Or the array is reset by the class from which you get the mutableFetchResults in the first place.

Objective-C NSArray

I'm new to Obj-C and iPhone SDK. The test application I'm stock with is a color switcher containing two buttons ("Back", "Forward") and one text label. The idea is to switch between rainbow colors (background) and setting an appropriate text label in a cyclic manner.
I declared NSArray (which is to contain colors names) in RainbowViewController.h, synthesized it in RainbowViewController.h and I can't add any string into that array.
This is "h" file:
#import <UIKit/UIKit.h>
#interface RainbowViewController : UIViewController {
IBOutlet UILabel *currentColorTextLabel;
NSArray *colorsArray;
NSString *msg;
}
#property (nonatomic, retain) IBOutlet UILabel *currentColorTextLabel;
#property (nonatomic, retain) NSArray *colorsArray;
#property (nonatomic, retain) NSString *msg;
- (IBAction) pressForwardButton;
- (IBAction) pressBackButton;
#end
This is "m" file:
#import "RainbowViewController.h"
#import <Foundation/Foundation.h>
#implementation RainbowViewController
#synthesize currentColorTextLabel;
#synthesize colorsArray;
#synthesize msg;
int currentArrayIndex = 0;
colorsArray = [[NSArray alloc] init]; //here i get "Initializer element is not constant" error message
[coloursArray addObject:#"Red"]; //here I get "Expected identifier or '(' before '[' token"
[coloursArray addObject:#"Orange"];
//etc
- (IBAction) pressForwardButton {
//here I'm going to increment currentArrayIndex, set an appropriate color, and update a currentColorTextLabel based on currentArrayIndex.
}
- (IBAction) pressBackButton {
}
//auto-genereted code here
#end
I'm new to obj-c as well, but I think you need to initialize the array with objects, or use an NSMutableArray if you want to add objects after it is created.
You have the code that should go in your init method just sitting out in the middle of the file. You can't set instance variables like that.
jasongetsdown is correct. You need to instantiate the NSArray object with the objects it will contain and nil terminated.
#"Red", #"Blue", nil
If you wish to have an array that you can change you need to make it a Mutable Array.
However, you have another problem here. Your property that you are synthesizing and allocating for is an object named colorsArray and you are trying to pass a method to a coloursArray object, two different spellings.