I'm currently learning some objective C but still have problems with the syntax and creating objects.
The Situation: I need a two dimensional "personsArray" which contains many personArrays each containing a NSString *name and a NSNumber *amount (double). Finally I want to calculate some stuff with the array data in another view but I'm far apart from that..
My Plan: Creating a NSMutable Object when the program starts. If I click the Button "Add Person", it creates a personArray with two fixed values (later it should grab those of textAreas). Here is my Code:
Person.h
#import <Foundation/Foundation.h>
#interface Person : NSObject{
NSNumber *amount;
NSString *name;
}
- (void) createPersonArray:(double)theAmount withName:(NSString*) aName;
#end
Person.m
#import "Person.h"
#implementation Person
- (void) createPersonArray:(NSNumber*)theAmount withName:(NSString*) aName{
NSArray* personArray = [NSArray arrayWithObjects:theAmount,aName,nil];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak,nonatomic) IBOutlet NSMutableArray *personsArray;
- (IBAction)addPerson:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "Person.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)addPerson:(id)sender {
Person *newPerson;
newPerson = [Person new];
[newPerson createPersonArray:100.00 withName:#"test"];
[_personsArray addObject:newPerson];
}
#end
I know that this wont work, but I don't know how to realize the stuff that I described above. If I build the program, the app starts. if I click the button the debugger jumps to the createPersonArray and outputs "Thread 1: EXC_BAD_ACCESS (code=1,address=0x40590000] and "Unused variable 'personArray'".
I watched many tutorials know but none of them explained this situation.. How must my code be structured to accomplish my goal? Am I on the right path or is it the wrong approach?
greetings
I think if you want save array to MutableArray, you only need create method in ViewController. If you create Person.h, i suggest you should save to MutableArray is Person Object. You can use code below:
Person.h:
#property (nonatomic, strong) NSNumber *amount;
#property (nonatomic, strong) NSString *name;
instead:
NSNumber *amount;
NSString *name;
Person.m:
#implementation Person
#synthesize name;
#synthesize amount;
- (void) createPersonArray:(double)theAmount withName:(NSString*) aName{
amount = [NSNumber numberWithDouble:theAmount];
name = aName;
}
ViewController.h
#property (strong,nonatomic) NSMutableArray *personsArray;
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
_personsArray = [[NSMutableArray alloc]init];
}
- (IBAction)addPerson:(id)sender {
Person *newPerson;
newPerson = [Person new];
[newPerson createPersonArray:100.00 withName:#"test"];
[_personsArray addObject:newPerson];
}
If you don't understand. You can comment below, i will help you.
When you need get contain, you can use:
for (Person *person in _personsArray){
NSLog(#"Amount: %# \n Name: %# \n ",ps.amount,ps.name,);
}
or
for (int i = 0; i< [_personsArray count]; i++){
Person *ps = [_personsArray objectAtIndex:i];
NSLog(#"Amount: %# - Name:%#",ps.amount,ps.name);
}
================================== UPDATE ===========================
double sumAmount = 0;
for (int i = 0; i < [_personsArray count]; i++){
Person *person = [_personsArray objectAtIndex:i];
sumAmount = sumAmount + [person.amount doubleValue];
}
double averageAmount = sumAmount / [_personsArray count];
NSLog(#"%f",averageAmount);
First, personsArray variable is not a outlet. So, remove outlet property and replace weak with strong:
#property (strong,nonatomic) NSMutableArray *personsArray;
Second, need to initialize NSMutableArray before using it, maybe in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
_personsArray = [NSMutableArray new];
}
Related
I have old project written on Objective-C. Need to do migration to Realm.
I created several objects/classes inheritance from RLMObject. When I do fetching objects only with one main object type (ConnectionRealm) - working fine, but if I do add (only add, not include, not use) to project two or more another classes (inheritance from RLMObject), like as FloorRealm class, APP crash on [ConnectionRealm allObjects] without any errors.
Also ConnectionRealm contains RLMArray of FloorRealm. App still crashing.
(Can`t solve and understand this few days.) Thanks.
Connection Model:
#import <Foundation/Foundation.h>
#import <Realm/Realm.h>
#import "FloorRealm.h"
#interface ConnectionRealm : RLMObject
#property int connectionID;
#property NSString *name;
#property NSString *localIPAddress;
#property NSString *localPort;
#property NSString *remoteIPAddress;
#property NSString *remotePort;
#property NSString *userName;
#property NSString *password;
#property NSString *deviceID;
#property RLMArray <FloorRealm *> *floors;
- (instancetype)initWith:(NSString *)name
localIP:(NSString *)localIPAddress
localPort:(NSString *)lPort
remoteIP:(NSString *)remoteIPAddress
remotePort:(NSString *)rPort
userName:(NSString *)userName
password:(NSString *)password
deviceID:(NSString *)deviceID;
#end
#import "ConnectionRealm.h"
#implementation ConnectionRealm
- (instancetype)initWith:(NSString *)name
localIP:(NSString *)localIPAddress
localPort:(NSString *)lPort
remoteIP:(NSString *)remoteIPAddress
remotePort:(NSString *)rPort
userName:(NSString *)userName
password:(NSString *)password
deviceID:(NSString *)deviceID {
if (self = [super init]) {
self.connectionID = [self incrementID];
self.name = name;
self.localIPAddress = localIPAddress;
self.localPort = lPort;
self.remoteIPAddress = remoteIPAddress;
self.remotePort = rPort;
self.userName = userName;
self.password = password;
self.deviceID = deviceID;
}
return self;
}
+ (NSString *)primaryKey { return #"connectionID"; }
- (int)incrementID {
RLMResults *objects = [ConnectionRealm allObjects];
return self.connectionID = [[objects maxOfProperty:#"connectionID"] intValue] + 1;
}
#end
FloorModel:
#import <Realm/Realm.h>
#interface FloorRealm : RLMObject
#property int floorID;
#property NSInteger floorNumber;
#property NSString *floorName;
- (instancetype)initWith:(NSInteger)floorNumber floorName:(NSString *)name;
#end
RLM_ARRAY_TYPE(FloorRealm)
#import "FloorRealm.h"
#implementation FloorRealm
- (instancetype)initWith:(NSInteger)floorNumber floorName:(NSString *)name {
if (self = [super init]) {
self.floorID = [self incrementID];
self.floorNumber = floorNumber;
self.floorName = name;
}
return self;
}
+ (NSString *)primaryKey { return #"floorID"; }
- (int)incrementID {
RLMResults *objects = [FloorRealm allObjects];
return self.floorID = [[objects maxOfProperty:#"floorID"] intValue] + 1;
}
#end
[SOLVED]
RLM_ARRAY_TYPE(FloorRealm) need put on ConnectionRealm in .h after #includes. But in official docs written another.
Also: #property RLMArray <FloorRealm *><FloorRealm> *floors; instead of #property RLMArray <FloorRealm *> *floors;
I created test project with the same models and seed all errors. Strange, but in original project Xcode not showing this errors.
I need to take information submitted by a user, store that information in an NSMutableDictionary, then store that NSMutableDictionary inside another NSMutableDictionary which is then encoded inside another class. For whatever reason, I can't seem to store the first NSMutableDictionary inside of the other.
I had to slim down the code that's in here due to work rules, so sorry if it seems to be missing anything. I only posted the parts that I'm having trouble with.
UserInfo.h:
#import <Foundation/Foundation.h>
#interface MyPlanInfo : NSObject <NSCoding>
#property (nonatomic, strong) NSMutableDictionary *emergencyDictionary;
#end
UserInfo.m:
#import <Foundation/Foundation.h>
#import "MyPlanInfo.h"
static NSString *emergencyDictionaryKey = #"emergencyDictionaryKey";
#implementation MyPlanInfo
#synthesize emergencyDictionary;
- (id) initWithCoder:(NSCoder *)coder
{
self = [super init];
self.emergencyDictionary = [coder decodeObjectForKey:emergencyDictionaryKey];
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:self.emergencyDictionary forKey:emergencyDictionaryKey];
}
#end
infoView.h
#import <UIKit/UIKit.h>
#import "MyPlanInfo.h"
#interface infoView : UIViewController <NSCoding>
{
NSMutableDictionary *emergencyContactInfo;
NSArray *userInfo;
NSArray *userKeys;
NSMutableArray *tempArray;
}
#property (nonatomic, strong) MyPlanInfo *myPlanInfoObject;
-(void)saveUserInfo;
-(void)loadUserInfo;
#end
infoView.m:
#import "infoView.h"
#interface infoView ()
#end
#implementation infoView
static NSString *userInfoKey = #"userInfoKey";
static NSString *userName;
-(void)viewDidLoad
{
[super viewDidLoad];
if(!self.myPlanInfoObject)
{
self.myPlanInfoObject = [[MyPlanInfo alloc] init];
}
[self loadUserInfo];
}
-(void)addToDictionary
{
emergencyContactInfo = [NSMutableDictionary dictionaryWithObjects:userInfo forKeys:userKeys];
if([userInfo count] != 0 || userInfo == nil)
{
self.myPlanInfoObject.emergencyDictionary = [NSMutableDictionary dictionaryWithObject:emergencyContactInfo forKey:userName];
}
[self saveUserInfo];
}
- (void)saveUserInfo
{
NSData *userInfoData = [NSKeyedArchiver archivedDataWithRootObject:self.myPlanInfoObject];
[[NSUserDefaults standardUserDefaults] setObject:userInfoData forKey:userInfoKey];
}
- (void)loadUserInfo
{
NSData *userInfoData = [[NSUserDefaults standardUserDefaults] objectForKey:userInfoKey];
if(userInfoData)
{
self.myPlanInfoObject = [NSKeyedUnarchiver unarchiveObjectWithData:userInfoData];
}
}
#end
In infoView.m, in the addToDictionary method, userInfo is an array of user inputted information, and userKey's is an array of key's. The emergencyContactInfo NSMutableDictionary works just fine, everything is in it, but when I try to set that as an object in a new NSMutableDictionary, for a key, it doesn't work. Everything is nil.
Anyone have any ideas on how what I'm doing wrong?
Edit: If you down vote, please leave a reason as to why so that I can avoid doing whatever I did wrong in the future.
In the following line you’re creating an instance of MyPlanInfo using plain alloc/init:
self.myPlanInfoObject = [[MyPlanInfo alloc] init];
However, at least in the code provided, you haven’t overridden init in MyPlanInfo, but instead, initWithCoder::
- (id) initWithCoder:(NSCoder *)coder
{
self = [super init];
self.emergencyDictionary = [coder decodeObjectForKey:emergencyDictionaryKey];
return self;
}
When you use just plain init, the MyPlanInfo’s emergencyDictionary instance variable will be nil. You should likely add something like the following to MyPlanInfo to override init:
- (id) init
{
if ((self = [super init])) {
emergencyDictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
That will assure that the newly created MyPlanInfo instance has a proper NSMutableDictionary that can be manipulated from other classes.
It seems if I do something like:
NSMutableArray *randomSelection = [[NSMutableArray alloc] init];
Then this needs to be in a function, and I can't modify it later using a different function.
I tried just instantiating it in the .h file,
#interface ViewController:
{
NSMutableArray *Values;
}
But then when I try to append to it during runtime, nothing happens. I try to append to it with this:
int intRSSI = [RSSI intValue];
NSString* myRSSI = [#(intRSSI) stringValue];
[Values addObject:myRSSI];
But the array remains empty when I do this.
How can I fix this?
The recommended way is to create a property;
// ViewController.h
#interface ViewController : UIViewController
{
}
#property (nonatomic, strong) NSMutableArray *values;
#end
Then override the getter for that property, to lazy-initialize it, i.e. the array will be allocated and initialized on first call of the NSMutableArray property's getter:
// ViewController.m
#interface ViewController ()
#end
#implementation ViewController
- (NSMutableArray *)values
{
if (!_values) {
_values = [[NSMutableArray alloc] init];
}
return _values;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//int intRSSI = [RSSI intValue];
//NSString *myRSSI = [#(intRSSI) stringValue];
//[self.values addObject:myRSSI];
// Keep it simple:
[self.values addObject:RSSI];
}
#end
I'm trying to write a calculator program, but I'm running into this error when pressing a particular key that is linked to the function expressionEvaluation. My calculator works fine, but I am trying to add in the ability to use/store variables. For this, I use the expressionEvaluation button. However, as soon as I press the button linked to that method, the whole app crashes, and xcode gives me the error EXC_BAD_ACCESS code=2. I'm new to objective-c, so I'm not sure how to debug this error. As far as I can tell, though, the issue is with the line
double result = [CalculatorBrain evaluateExpression:self.brain.expression usingVariableValues:testValues];
...in my view controller. I set a break point before this line and it didn't crash, but setting it at this line resulted in the crash I'm experiencing.
I tried to cut the code down below, and have included only the things directly linked to the expressionEvaluation button. Thank you for your help!
Here's the .h for my brain method:
// CalculatorBrain.h
#import <Foundation/Foundation.h>
#interface CalculatorBrain : NSObject
- (void) pushOperand:(double)operand;
- (void) setVariableAsOperand:(NSString *)variableName;
- (void) performWaitingOperation;
- (double) performOperation:(NSString *)operation;
#property (readonly) id expression;
+ (double)evaluateExpression: (id)anExpression
usingVariableValues: (NSDictionary *)variables;
+ (NSSet *)variablesInExpression:(id)anExpression;
+ (NSString *)descriptionOfExpression:(id)anExpression;
+ (id)propertyListForExpression:(id)anExpression;
+ (id)expressionForPropertyList:(id)propertyList;
#end
Here's the .m:
// CalculatorBrain.m
#import "CalculatorBrain.h"
#define VARIABLE_PREFIX #"^"
#interface CalculatorBrain()
#property (nonatomic) double operand;
#property (nonatomic, strong) NSString *waitingOperation;
#property (nonatomic) double waitingOperand;
#property (nonatomic) double storedOperand;
#property (nonatomic) NSMutableArray *internalExpression;
#end
#implementation CalculatorBrain
#synthesize operand = _operand; //operand in use
#synthesize waitingOperation = _waitingOperation; //waiting to be computed
#synthesize waitingOperand = _waitingOperand; //waiting to be used
#synthesize storedOperand = _storedOperand; //stored in memory
#synthesize internalExpression = _internalExpression; //private expression stored
#synthesize expression = _expression;
- (id) expression {;
return [NSMutableArray arrayWithArray:self.internalExpression];
}
//here I have instance methods that add objects to the array internalExpression
//these work fine as far as I can tell
+ (double) evaluateExpression:(id)anExpression usingVariableValues:(NSDictionary *)variables {
double result = 0;
int count = [anExpression count];
CalculatorBrain *brain;
for (int i = 0; i < count; i++) {
if([[anExpression objectAtIndex:i] isKindOfClass:[NSNumber class]]) {
double operand = [[anExpression objectAtIndex:i] doubleValue];
[brain pushOperand:operand];
}
if([[anExpression objectAtIndex:i] isKindOfClass:[NSString class]]) {
NSString *string = [anExpression objectAtIndex:i];
if([string characterAtIndex:0] == '^') {
NSString* variable = [NSString stringWithFormat:#"%c",[string characterAtIndex:1]];
double valueOfVariable = [[variables objectForKey:variable] doubleValue];
[brain pushOperand:valueOfVariable];
}
else {
NSString* operator = [anExpression objectAtIndex:i];
result = [brain performOperation:operator];
}
}
}
return result;
}
#end
Here's the .h for my view controller:
// CalcViewController.h
#import <UIKit/UIKit.h>
//view controller for calculator
#interface CalcViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *display; //real-time display
#property (strong, nonatomic) IBOutlet UILabel *miniDisplay; //past display
#property (strong, nonatomic) IBOutlet UILabel *memDisplay; //display stored digits
- (IBAction)digitPressed:(UIButton *)sender; //pressed number
- (IBAction)operandPressed:(UIButton *)sender; //pressed operation
- (IBAction)variablePressed:(UIButton *)sender; //pressed variable
- (IBAction)expressionEvaluation:(UIButton *)sender; //evaluate expression with variables
#end
Here's the .m:
// CalcViewController.m
#import "CalcViewController.h"
#import "CalculatorBrain.h"
#interface CalcViewController ()
#property (nonatomic, strong) CalculatorBrain *brain;
#property (nonatomic) BOOL userIsInTheMiddleOfTypingANumber;
#end
#implementation CalcViewController
- (CalculatorBrain *) brain {
if (!_brain) _brain = [[CalculatorBrain alloc] init];
return _brain;
}
- (IBAction)expressionEvaluation:(UIButton *)sender {
NSDictionary* testValues = [NSDictionary dictionaryWithObjectsAndKeys:#"x", 2, #"y", 3, #"z", 4, nil];
double result = [CalculatorBrain evaluateExpression:self.brain.expression usingVariableValues:testValues];
NSString *resultString = [NSString stringWithFormat:#"%g", result];
self.display.text = resultString;
}
#end
EDIT: Just as a side note, I am not getting any errors, only one warning: incomplete implementation. This is because I haven't finished a couple class methods yet, but I don't think it is causing the crash.
NSDictionary* testValues = [NSDictionary dictionaryWithObjectsAndKeys:#"x", 2, #"y", 3, #"z", 4, nil];
turned out to be the erroneous line. It should have been:
NSDictionary* testValues = [NSDictionary dictionaryWithObjectsAndKeys:#"x", [NSNumber numberWithInt:2], #"y", [NSNumber numberWithInt:3], #"z", [NSNumber numberWithInt:4], nil];
Thanks to everyone who helped!
You will get more information on the code line raising the exception by adding an exception breakpoint in xCode.
Let me preface this question by saying that I believe it to be a memory management mistake on my end. I just can't seem to figure out why it is happening.
I have a viewcontroller and a model class named Part.
#import <Foundation/Foundation.h>
#interface Part : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *partType;
#property (nonatomic, strong) NSString *description;
#property (nonatomic, strong) NSNumber *price;
- (id)initWithName:(NSString *)name AndType:(NSString *)type;
#end
In the view controller I have a property set as follows:
#property (nonatomic, strong) Part *part;
In the init function of ViewController I create some static arrays and create objects out of them:
- (id)init {
self = [super init];
self.partList = [[NSMutableArray alloc] init];
NSArray *inputArray = #[#"Part1",
#"Part2",
#"Part3",
#"Part4",
#"Part5",
#"Part6",
#"Part7",
#"Part8"];
NSString *tempType = #"PartCategory";
// Add dummy static data
for (int i = 0; i < [inputArray count]; i++) {
Part *partInput = [[Part alloc] initWithName:[inputArray objectAtIndex:i] AndType:tempType];
//partInput.name = [inputArray objectAtIndex:i];
//partInput.partType = tempType;
NSLog(#"Inserting Part %#", partInput);
[self.partList addObject:partInput];
}
return self;
}
The NSLog I call in that loop returns Inserting Part *nil description* for every part. I just can't track down what is happening here.
EDIT: Here is the initWithName method from Part that the controller uses:
- (id)initWithName:(NSString *)name AndType:(NSString *)type {
if(self = [super init]) {
self.name = name;
self.partType = type;
}
return self;
}
When using %# to print NSObject, it calls debugDescription that by default calling the description method of that object and your Part object always have nil description.
You better solve this by changing the description property name to something else, because it conflicts with the description method of NSObject.
See also: NSObject description and debugDescription