I've been tinkering all day, and I can't seem to fix this error.
Here's the code:
//
// main.m
// Learning ObjC
//
// Created by Nickirv on 8/9/15.
// Copyright (c) 2015 Nickirv. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface Person: NSObject{
int age;
int weight;
}
-(void) print;
-(void) setAge: (int) a;
-(void) SetWeight: (int) w;
#end
And it outputs this issue:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I would appreciate any help! Thank you very much!
You can't delete the main boilerplate code:
int main(int argc, const char * argv[]) {
#autoreleasepool {
}
return 0;
}
In the end Objective-C is "C" and the program starts execution by calling main. Additionally Objective-C code needs to execute in an autoreleasepool.
You define class #interfaces and #implemtations outside of (generally above) the boilerplate but the first line of code to run must be within the autoreleasepool scope {}.
Here is an example Objective-C program similar to what the OP seems to want using #properties for simplicity and demonstration.
It is important to study Objective-C documentation until the following code is fully understood, td;dr does not work for this.
#import <Foundation/Foundation.h>
#interface Person: NSObject
#property int age;
#property int weight;
- (void)print;
#end
#implementation Person : NSObject
- (void)print {
printf("Age: %i, weight: %i", self.age, self.weight);
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
Person *don = [[Person alloc] init];
don.weight = 130;
don.age = 23;
[don print];
}
return 0;
}
Output:
Age: 23, weight: 130
I just started out programming in Objective C. This is very simple stuff but im wondering what im missing on my knowledge of properties, as far as I understand this should work but it gives me the error:
Property 'score' not found on object of type 'Player *'
I have a Player class and the code as follows below, each bolded is a separate file
Player.h has:
#import <Foundation/Foundation.h>
#interface Player : NSObject
#property int score;
#end
Player.m has:
#import "Player.h"
#implementation Player
- (id)init {
self = [super init];
if (self){
_score = 5000;
}
return self;
}
#end
main.m has
#import <Foundation/Foundation.h>
#import "Player.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Player *firstPlayer = [[Player alloc] init];
NSLog(#"The default score is %i", [firstPlayer score]);
}
return 0;
}
Player.h is missing the following line which should go between the #import and #property lines:
#interface Player : NSObject
Where NSObject may be a different class, but needs to be whatever you intend to be subclassing.
I'm currently teaching myself Objective-C with the Big Nerd Ranch guide (2nd edition) and I have not had a problem up until chapter 21. I checked the book's forum, but it was of no help because most people there are newbies with spaghetti code, and I do not want to adopt bad habits...I am a beginner too, as this is my first major language, but spaghetti code is obvious when you see it.
I have to take my code from a previous chapter and make a tool that creates an instance of a BNRPortfolio class and fills it with stock holdings (must also sum up the portfolio's current value). Then I have to add a symbol property to BNRStockHolding that holds the stock ticker symbol as an NSString.
I am just completely confused as to where to add the code to do this and how to begin. From my research online, this chapter was poorly written and is where most readers have gotten stuck...the authors even agreed that in future editions (if ever because of Swift moving in) they would re-write the entire chapter.
Currently, my code from a previous chapter looks like this:
BNRStockHolding.h
#import <Foundation/Foundation.h>
#interface BNRStockHolding : NSObject
#property (nonatomic) float purchaseSharePrice;
#property (nonatomic) float currentSharePrice;
#property (nonatomic) int numberOfShares;
- (float)costInDollars;
- (float)valueInDollars;
#end
BNRStockholding.m
#import "BNRStockHolding.h"
#implementation BNRStockHolding
- (float)costInDollars
{
return _purchaseSharePrice * _numberOfShares;
}
- (float)valueInDollars
{
return _currentSharePrice * _numberOfShares;
}
#end
Next, I had to add foreign stocks with a conversion rate that converted the values and cost into U.S. dollars:
BNRForeignStockHolding.h
#import <Foundation/Foundation.h>
#import "BNRStockHolding.h"
#interface BNRForeignStockHolding : BNRStockHolding
#property (nonatomic) float conversionRate;
#end
BNRForeignStockHolding.m
#import "BNRForeignStockHolding.h"
#implementation BNRForeignStockHolding : BNRStockHolding
- (float)costInDollars
{
float foreignCostInDollars = super.costInDollars;
return _foreignCostInDollars * _conversionRate;
}
- (float)valueInDollars
{
float foreignValueInDollars = super.valueInDollars;
return _foreignValueInDollars * _conversionRate;
}
#end
My main file:
main.m
#import <Foundation/Foundation.h>
#import "BNRForeignStockHolding.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
BNRStockHolding *stock0 = [[BNRStockHolding alloc]init];
BNRStockHolding *stock1 = [[BNRStockHolding alloc]init];
BNRStockHolding *stock2 = [[BNRStockHolding alloc]init];
BNRForeignStockHolding *stock3 = [[BNRForeignStockHolding alloc]init];
stock0.purchaseSharePrice=2.30;
stock0.currentSharePrice=4.50;
stock0.numberOfShares=40;
stock1.purchaseSharePrice=12.19;
stock1.currentSharePrice=10.56;
stock1.numberOfShares=90;
stock2.purchaseSharePrice=45.10;
stock2.currentSharePrice=49.51;
stock2.numberOfShares=210;
stock3.purchaseSharePrice=43.05;
stock3.currentSharePrice=28.31;
stock3.numberOfShares=15;
stock3.conversionRate=0.3;
NSMutableArray *stocks = [NSMutableArray arrayWithObjects:stock0, stock1, stock2, stock3, nil];
for (BNRForeignStockHolding *s in stocks) {
float a = s.purchaseSharePrice;
float b = s.currentSharePrice;
int c = s.numberOfShares;
if ([s isMemberOfClass:[BNRForeignStockHolding class]]) {
float d = s.foreignCostInDollars;
float e = s.foreignValueInDollars;
NSLog(#"\n Purchase Price: %.2f\n Current Price: %.2f\n Number of Shares %d\n Cost in Dollars %f\n Value in Dollars %f\n", a, b, c, d, e);
}
else {
float d = s.costInDollars;
float e = s.valueInDollars;
NSLog(#"\n Purchase Price: %.2f\n Current Price: %.2f\n Number of Shares %d\n Cost in Dollars %f\n Value in Dollars %f\n", a, b, c, d, e);
}
}
}
return 0;
}
I tried this:
In BNRStockHolding.h, I created an instance variable:
- (float)currentTotalValue
and in BNRStockHolding.m, I implemented it like this:
-(float)currentTotalValue
{
return _currentTotalValue = _currentSharePrice * _numberOfShares;
}
Then in main.m, I added this to the 'for' function in my stocks array:
float f = s.currentTotalValue;
Then added %.2f#, f to my NSLog print out.
It worked perfectly except for this caveat:
It simply gave me the value of each individual stock without converting the foreign stocks. I somewhat understand why, but the chapter did not explain thoroughly how to attack such a problem, so I am totally lost. I couldn't even attempt adding the stock ticker symbol because I wasn't sure where to implement it.
When adding up the total value of my portfolio by hand, converted foreign values included, the total should be $17,774.895. Keep in mind that these stocks are pretend, as is the conversion rate, etc.
Thank You for any help, it is greatly appreciated!
EDIT TO ADD
Problem solved, I had to rewrite my BNRStock and BNRForeign .h and .m files with overrides for costInDollars and valueInDollars, as well as add an exception for NSLog to print out separate results for each via an [NSString stringWithFormat:] method. Then I added the sum code recommended with a few tweaks and everything worked well. I also added the stock tickers with no problem by defining symbol as a pointer in my .h and .m files and then including them in the [NSString stringWithFormat:] printout command.
Shoutout to danH for noticing that my costInDollars and valueInDollars should have been overridden to work for both BNRStock and BNRForeign classes, as that was the main issue with my program.
Not familiar with the book, but it sounds like BNRPortfolio is a new class, deserving of a new .h and .m file. You should crib naming conventions from the work you've done so far. A start would look something like this:
// in BNRPortfolio.h
#class BNRStockHolding;
#interface BNRPortfolio : NSObject
- (void)addHolding:(BNRStockHolding *)holding;
- (float)portfolioValue;
#end
// in BNRPortfolio.m
#import "BNRPortfolio.h"
#import "BNRStockHolding.h"
#interface BNRPortfolio () // fixed typo here
#property (strong, nonatomic) NSMutableArray holdings;
#end
#implementation BNRPortfolio
- (id)init {
self = [super init];
if (self) {
_holdings = [NSMutableArray array];
}
return self;
}
- (void)addHolding:(BNRStockHolding *)holding {
[self.holdings addObject:holding];
}
- (float)portfolioValue {
float sum = 0;
for (BNRStockHolding *holding in self.holdings) {
sum += [holding valueInDollars];
}
return sum;
}
#end
You should be able to alloc-init one of these, then add several holdings, foreign and domestic, and then ask for the portfolio value.
EDIT - call it from main this way:
#import <Foundation/Foundation.h>
#import "BNRStockHolding.h"
#import "BNRForeignStockHolding.h"
#import "BNRPortfolio.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
// build stock0, stock1, stock2, stock3 just as you have them, then...
BNRPortfolio *portfolio = [[BNRPortfolio alloc] init];
[portfolio addHolding:stock0];
[portfolio addHolding:stock1];
[portfolio addHolding:stock2];
[portfolio addHolding:stock3];
NSLog(#"The total value of the portfolio in USD is %f", [portfolio portfolioValue]);
}
return 0;
}
I may just be dumb, but I don't see in your code where you're totaling the entire portfolio value. I see where each stock's total value is calculated. Maybe you need outside the for loop:
float f = 0.0;
then inside the for loop:
f += e;
Here's also just a couple of thoughts on maybe a different approach.
I don't think I'd put any code in main.m. I'd leave it as:
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[])
{
return NSApplicationMain(argc, argv);
}
I'd do the work in the Objective C classes, and there are a number of ways to do this, but here's one (leaving out some details):
I'd enable ARC so I don't need to worry about memory management.
In my AppDelegate.h file I might have:
#import <Foundation/Foundation.h>
#import "BNRStockHolding.h"
#import "BNRPortfolio.h"
#import "BNRForeignStockHolding.h
#interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
{
#public
BNRStockHolding *bnrStockHolding;
BNRPortfolio *bnrPortfolio;
BNRForeignStockHolding *bnrForeignStockHolding;
}
then in the AppDelegate.m file:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
bnrStockHolding = [[BNRStockHolding alloc] init;
bnrPortfolio = [[BNRPortfolio alloc] init];
bnrForeignStockHolding = [[BNRForeignStockHolding alloc] init];
}
Then in another class (lets say BNRPortfolio) in the .h file, I might have:
#class AppDelegate;
#interface BNRPortfolio : NSObject
{
#public
NSMutableArray *holdings;
#private
AppDelegate *appDelegate;
}
- (void)addHolding:(BNRStockHolding *)holding;
- (float)portfolioValue;
And in the BNRPortfolio.m file:
#import "BNRPortfolio.h"
#import "AppDelegate.h"
#implementation BNRPortfolio
- (id)init
{
self = [super init];
if (self)
{
holdings = [[NSMutableArray alloc]init];
appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
}
return self;
}
If you set up the variables and an AppDelegate pointer in your other classes, then in those classes, for example, the portfolioValue method could be accessed like:
float portValue = [appDelegate->brnPortfolio portfolioValue];
and holdings could be accessed like:
[appDelegate->brnPortfolio->holdings addObject:holding];
This is obviously just a skeleton of the application (but it's already too long), but I hope you get the idea. In programming there are always many ways to get things accomplished, and sometimes one approach is better than another depending on the circumstances. I just happen to rarely use main.m.
One last comment is that the reason we say #class AppDelegate in the class .h files and import AppDelegate.h in the .m files is that to do otherwise would set up a circular reference, which the compiler will not allow.
That is AppDelegate.h is importing BNRPortfolio.h and BNRPortfolio.h would be importing AppDelegate.h. That's a circular reference.
So we use the #class statement to tell the compiler not to worry for now, we'll define the class later, and then we import AppDelegate.h in the class .m files.
I know I'm probably making a stupid mistake but I'm working my way through the book Programming in Objective-C and I'm getting a couple of errors but I cant seem to find the mistake.
person.m
#import "person.h"
#implementation person{
int age;
}
-(void) print{
NSLog(#"the person is %i years old", age);
}
-(void) setAge:(int)a{
age = a;
}
#end
person.h
#import <Foundation/Foundation.h>
#interface person : NSObject
-(void) print;
-(void) setAge: (int)a;
#end
main
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
person *newPerson; //error is on this line use of undeclared identifier:person
}
return 0;
}
You need to import person.h header in all files you want to use Person class, so add
#import "person.h"
line to your main file
This question already has answers here:
Objective-C #import loop
(2 answers)
Closed 9 years ago.
#import <Foundation/Foundation.h>
#import "Asset.h"
#interface Person : NSObject{
int pin;
NSMutableArray* assets;
}
#property int pin;
-(void) addAsset: (Asset*) iasset; //producing error
#end
Trying to code the interface of a "Person" class that contains an array of "assets".
The line
-(void) addAsset: (Asset*) iasset;
produces an error. XCode says, "Expected a type". Can someone tell me where I'm going wrong? I can provide whatever other code is needed.
Asset.h :
#import <Foundation/Foundation.h>
#import "Person.h"
#interface Asset : NSObject{
NSString* label;
int value;
Person* holder;
}
#property int value;
-(void) setHolder: (Person*)iholder;
-(void) setLabel: (NSString*)iname;
#end
You have a circular dependency in your header files. You can fix it by removing #import "Person.h" in Asset.h and replacing it with #class Person;. This change will tell the compiler about the existence of the Person class without requiring the header to be imported.
Likewise, you could instead replace #import "Asset.h" in Person.h with #class Asset;.
You'll still want to include the correct headers from your implementation files.