Get String From Array to call method - objective-c

I'm trying to get a string in my call from an array. But have no luck. It's being passed to another class.
MainClass.h
#import First
#class First;
#interface MainClass : UIViewController{
NSMutableArray *listArray;
}
///////////////////
MainClass.m
First *first = [[First alloc] init];
listArray = [[NSMutableArray alloc]init];
[listArray addObject:#"first"];
[listArray addObject:#"second"];
int Aslot = 0;
int sumA;
float level = 5, insample = 10;
NSString *slotA =[listArray objectAtIndex:ASlot];
sumA = [slotA out:insample andlevels:level];
/////////
First.h
-(float)out:(float)insample andlevels:(float)level;
First.m
-(float)out:(float)insample andlevels:(float)level{
float outsample = insample + 10 * level;
return outsample;
}
I want slotA (the Class) to equal a string from the array "first" or "second", so it can call the method.
I have a table which when I select first, it sends samples and other parameters to another class where it does processing then returns back to MainClass.
sumA = [first out:insample andlevels:level];
But I'm getting an error saying that NSString may not respond to my parameters out:andlevels. Please help..

Edit:
If I understand correctly, you want to dynamically create an instance of a class whose name you have stored as an NSString. You can do that this way:
int Aslot = 0;
int sumA;
float level = 5, insample = 10;
NSString *className = [listArray objectAtIndex:Aslot];
Class sampler = objc_getClass([className UTF8String]);
id instance = [[sampler alloc] init];
sumA = [instance out:insample andlevels:level];
// Do whatever you want with sumA here.
[instance release];
If you're doing this a lot, you'll probably want to either keep the instance around or store the classes in the array instead of their names, depending on exactly what you are doing.

Related

Creating NSString results in null

I am trying to initialize an NSString. I tried initWithString: but this becomes invalid because the NSString becomes an NSPlaceholderString. I switched to UTF8string, but it returns a null value.
code below:
- (void) test:(NSString*)thing {
id (*p_objc_msgSend)(id p, SEL sel, ...);
id (*p_objc_getClass)(const char *s);
Class class;
p_objc_getClass = objc_getClass;
p_objc_msgSend = objc_msgSend;
NSString *s;
class = (*p_objc_getClass)( "NSString");
//SEL init = #selector(initWithString:);
s = (*p_objc_msgSend)(class, #selector(alloc));
s = (*p_objc_msgSend)(s, #selector(initWithUTF8String:), "AAA");
NSLog(#"Value of %#", s);
}
NSString is a class cluster with multiple private subclasses. NSPlaceholderString is a subclass of NSString so you can continue to use that object as any other NSString.

Objective-C Accessing Superclass Methods when Object Might be Superclass or Subclass

I'm an Objective-C noob working through a tutorial and I'm hitting a strange snag I want to understand better.
I'm looping to make a portfolio of stock objects that have a 50/50 chance of being a "foreignStock" or just being "stock" - the difference being a conversion rate property. The object stock is a superclass, with foreignStock being a subclass of stock.
I want to create a pointer, flip a coin to decide which type it is, and then assign the values I need. Since both the subclass and superclass have things like currentSharePrice, why can't I set them after the coin toss?
This is my main.m for review:
int main(int argc, const char * argv[]) {
#autoreleasepool {
// Declare portfolio and set the conversion rate
BNRPortfolio *mikesPortfolio = [[BNRPortfolio alloc] init];
NSUInteger globalConRate = 1.2;
// Array of ticker names - remove them as they are used
NSMutableArray *tickerNames = [[NSMutableArray alloc] init];
[tickerNames addObject:#"ibm"];
[tickerNames addObject:#"ppg"];
[tickerNames addObject:#"google"];
[tickerNames addObject:#"vrzn"];
[tickerNames addObject:#"apple"];
[tickerNames addObject:#"barq"];
// Create and add the stocks to the portfolio
for (int i = 0; i < 6; i++) {
id newStock;
// Coin flip to determine type
NSUInteger randomType = random() % 2;
if (randomType == 0) {
newStock = [[BNRStockHolding alloc] init];
} else {
newStock = [[BNRForeignStockHolding alloc] init];
newStock.conversionRate = globalConRate;
}
// Assign remaining values
newStock.purchaseSharePrice = 15 * (random() % i);
newStock.currentSharePrice = newStock.purchaseSharePrice * 1.4;
NSUInteger randomTickerValue = random() % [tickerNames count];
newStock.symbol = tickerNames[randomTickerValue];
[tickerNames removeObjectAtIndex:randomTickerValue];
[mikesPortfolio addHoldings:newStock];
}
}
The line inside the else{} block newStock.conversionRate... gives an Xcode pre-compile error stating "property not found for object of type __strong id" - I guess because it can't tell if newStock will actually be what I just declared it to be? But the assign statements at the end of main.m are showing the same line error as though newStock doesn't have those properties, even though BOTH classes will have access to them.
How do I make newStock understand that it will definitely be a class that has those properties but might ALSO have that conversion rate associated with the subclass?
I tried this:
BNRStockHolding newStock; <-- starting with superclass
// Coin flip to determine type
NSUInteger randomType = random() % 2;
if (randomType == 0) {
newStock = [[BNRStockHolding alloc] init];
} else {
newStock = [[BNRForeignStockHolding alloc] init];
newStock.conversionRate = globalConRate;
}
Which will make the errors on the bottom lines go away but still won't compile at the subclass method in the else{} block.
Where did I go wrong?
(I'm going to assume this is actually main.m, not main.c.)
Your primary mistake is using id rather than types.
id newStock;
This says that newStock is "some kind of object, I have no idea what." In ObjC, id can be sent any message, but it does not have any properties. So you can't use dot-notation on it. There are ways around that (don't use dot notation), but the better solution is to use a type:
BNRStockHolding *newStock = nil;
That will cause a problem here:
newStock = [[BNRForeignStockHolding alloc] init];
newStock.conversionRate = globalConRate;
Which you can fix this way:
BNRForeignStockHolding *foreignStock = [[BNRForeignStockHolding alloc] init];
foreignStock.conversionRate = globalConRate;
newStock = foreignStock;
But if the only thing that makes a foreign stock "foreign" is that it has a conversion rate, I would strongly recommend against subclassing here. Just make all stocks have a conversion rate. If it's domestic, make the conversion rate 1.

Cannot Get Data from Custom Class

I looked around for an answer to this because it seems simple but I could not seem to find something that suffised. I am trying to test a program I have with fake data. I created a StudentData class that possesses a attributes for a student and also has an array to hold them all.
When another class needs them they call a getStudent method (which is the only public part of this class thus far) and sends an ID number to get the name of that student back.
My problem is that I cannot figure out how to parse through the student array to match the student ID numbers with the one that was passed in. Holding the same problem, I cannot figure out how to pull the name out of a student object either.
Here is my code so far:
// StudentData.m
#import "StudentData.h"
#interface StudentData() {
NSString *ID;
NSString *firstName;
}
#property (nonatomic, strong) NSMutableArray *studentArray;
#end
#implementation StudentData
#synthesize studentArray = _studentArray;
- (NSMutableArray *)studentArray {
if(!_studentArray) _studentArray = [[NSMutableArray alloc] init];
return _studentArray;
}
- (void)awakeFromNib {
NSArray *idA = [NSArray arrayWithObjects:#"111", #"685", nil];
NSArray *fnA = [NSArray arrayWithObjects:#"Mark", #"Sam", nil];
for(int i = 0; i < idA.count; i++) {
StudentData *tempCurrentStudent = [[StudentData alloc] init];
ID = [idA objectAtIndex:i];
firstName = [fnA objectAtIndex:i];
[self.studentArray addObject:tempCurrentStudent];
}
}
- (NSString *)getStudentsFirstName:(NSString *)studentID {
NSString *firstName;
for(int i = 0; i < self.studentArray.count; i++) {
if([studentID isEqualToString:[[self.studentArray objectAtIndex:i] self.firstName]]) { // ERROR
fN = [[self.studentArray objectAtIndex:i] self.firstName]; // ERROR
}
}
return firstName;
}
#end
The Error I keep getting is: Expect ']' and the error is pointing to the "self.firstName" lines.
If I use "[self.studentArray objectAtIndex:i].firstName;" I get the error: Property 'firstName' not found on object of type 'id' I even get this error if I make "firstName" a property (both local or public). This makes sense because the array is technically filled with 'id' types. I also know that unlike java I cannot use generics or anything like that.
Any help would be much appreciated and if it needs clarification please let me know! By the way this is for an ipod/ipad app if that helps at all.
Thanks!
Two things :
You're having a name conflict here. You are having a local variable called firstName and the parameter passed to your problem function has the same name.
firstNameis NOT a property unless you define it as one. In this case it's just a normal local variabel. Means that you can't access it using self.firstName but just by firstName. That's one of the reason the coding guidelines say that you should name local variables starting with an underscore ( as you are already doing in the studentArrayproperty). This way you can distinguish if it is a local variable or a property.
Best,
Flo

objective-c how to call different values based on user selection of class

i am working on a sort of simulator for a game i am designing and am in need of a bit of help. the basic simulator will run from within GNUstep's compiler via dos i suppose is the best way to describe it. The basic idea is this: when the program loads it will ask to select the ID of a unit from a populated list upon selection it references a class and creates a new class and its methods then it asks for a defending unit ID, and follows the similar path of creating that new class and methods. i apologize if my terminology is wrong on methods and such.
in any case so far all that i want to have happen happens. i can call the new units via entry by using cases.
on to the hard part:
#interface Unit1: NSObject { #interface Unit2: NSObject {
int unitType; int unitType;
int attackInfantry; int attackInfantry;
int attackArmored; int attackArmored;
int attackAerial; int attackAerial;
int attackAquatic; int attackAquatic;
int attackHeroic; int attackHeroic;
int attackHP; int attackHP;
int attackBAV; int attackBAV;
int attackBDV; int attackBDV;
} }
-(void) print; -(void) print;
-(void) Stats; -(void) Stats;
#end #end
so heres an example of my interface we have two units here: Next up is the implementation:
#implementation Marine #implementation Speeder
-(void) Stats -(void) Stats
{ {
attackHP = 10; attackHP = 10;
attackBAV = 20; attackBAV = 23;
attackBDV = 10; attackBDV = 10;
unitType = 1; unitType = 2;
attackInfantry = 15; attackInfantry = 23;
attackArmored = 10; attackArmored = 18;
attackAerial = 0; attackAerial = 9;
attackAquatic = 7; attackAquatic = 15;
attackHeroic = 0; attackHeroic = 0;
} }
so heres the plan, what i would like to do is have some way of recognizing the unitType and then selecting the proper attack value. so in this case 1 equals infantry and 2 equals armored. for this example the first unit would be using attackArmored = 10; because the program recognizes that the second unit has unitType = 2; and the second unit would use attackInfantry = 23; for the same reason, it knows that it is attacking an infantry type unit.
im not sure if i have the units set up as properly as they should be, but im building this simulator with the intent on learning as i am new to objective-C and the world of code.
i hope this all made sense and i was able to get my question across...
Seems like both Unit1 (should probably be InfantryUnit) and Unit2 (should probably be SpeederUnit) should have an abstract parent called Unit. All the properties (attackHP, etc) would be defined in Unit.
The -init method of each subclass of Unit would set up the hit points, attack values, etc of that particular unit.
I would also have a method on Unit that goes something like this:
typedef enum {
UnitTypeInfantry = 1,
UnitTypeSpeeder = 2
} UnitType;
+ (Unit *) unitWithType:(UnitType)type {
if (type == UnitTypeInfantry) {
return [[[InfantryUnit alloc] init] autorelease];
} else if (type == UnitTypeSpeeder) {
return [[[SpeederUnit alloc] init] autorelease];
}
return nil;
}
Rather than a bunch of individual attack variables for all the different opponent types, you could make a single variable attackValues that's an NSDictionary. The keys of the dictionary would be the opponent type, and the values would be the attack amounts. (Another possibility would be to use an NSArray indexed by unit type, assuming your types are all small integers, but the key/value approach is more flexible.)
For example,
#interface Unit1: NSObject {
int unitType; // numeric type (1, 2, ...)
NSString *unitTypeName; // "Infantry", "Armored", ...
NSDictionary *attackValues;
...
}
-init {
unitType = UnitTypeInfantry;
unitTypeName = #"Infantry";
// Set attack values for other kinds of units
attackValues = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:15], #"Infantry",
[NSNumber numberWithInt:10], #"Armored",
[NSNumber numberWithInt:0], #"Aerial",
[NSNumber numberWithInt:7], #"Acquatic",
[NSNumber numberWithInt:0], #"Heroic",
nil];
}
Then to get the attack value for a particular opponent type, all you need to do is:
int attack = [[attackValues objectForKey:[opponent unitTypeName]] intValue];
The advantages of using a dictionary-driven design instead of individual properties are:
1) You don't have to write a lot of if statements like:
if (opponent.unitType == 1)
attack = attackInfantry;
else if ((opponent.unitType == 1)
attack = attackArmored;
else if ...
2) If you add a new unit type, you don't need to add a new variable to every other unit type.

Declare Dynamic Array

How can I declare dynamic array? For example:
int k=5;
I want to have an array like below:
int myArray[k];
if i read the question right.. (unlikely at this point)
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:k];
Sometimes true arrays (not NSArray) are really needed. See for example indexPathWithIndexes:length: in NSIndexPath, it take array of uintegers as parameter. For array allocation you should use the following approach:
NSUInteger *arr = (NSUInteger*)malloc(elementsCount * sizeof(NSUInteger) );
arr[0] = 100;
free(arr);
In Objective-C, the standard way to do this is to use the NSMutableArray class. This is a container that can hold any object (note that int is not an object! You'll have to wrap your integers in NSNumber.) Quick example:
NSMutableArray* someIntegers = [[NSMutableArray alloc] initWithCapacity:1];
[someIntegers addObject:[NSNumber numberWithInt:2]];
//I've added one thing to my array.
[someIntegers addObject:[NSNumber numberWithInt:4]];
//See how I can put more objects in than my capacity allows?
//The array will automatically expand if needed.
//The array now contains 2 (at index 0) and 4 (at index 1)
int secondInteger = [[someIntegers objectAtIndex:1] intValue];
//Retrieving an item. -intValue is needed because I stored it as NSNumber,
//which was necessary, because NSMutableArray holds objects, not primitives.
Well in my book it's ok to use VLAs in Objective-C.
So something like
int foo = 10;
int bar[foo];
is allowed. Of course this is not a dynamic array as in automatically adjusting its size. But if you only need a native array on the stack that's fine.
You can use Objetive-C++.
First rename your class like this: MyClass.mm the ".mm" extension tells Xcode that this clas is a Objetive-C++ class, not a Objetive-C class.
then you can use dynamics C++ arrays like this:
int *pixels = new int[self.view.size.width];
for (int offset = 0; offset = self.view.size.width; offset++) {
pixeles[offset] = rawData[offset];
}
then you can pass "pixels" in a method:
Scan *myScan = [[Scan alloc] initWhithArray:pixels];
the method "initWithScan" is declared like this:
-(id)initWithArray:int[]pixels;
the "initWithScan" implementation is like this:
-(id)initWithScan:int[]pixels {
if (self = [super init]) {
for (int i = 0; i < self.myView.size.width; i++) {
NSLog(#"Pixel: %i", pixels[i];
}
}
return self;
}
I hoppe this was useful.