How do you set the text of a label to an array value? - objective-c

I would like to set a value of my array to a label.
Array declaration:
//
// ViewController.h
// Cornell Notes
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
NSString *details[8][8];
NSString *subtitles[8];
}
I am not allowed to do:
self.label.text = subtitles[0];
How can I do this?

This:
#interface ViewController : UIViewController{
NSString *details[8][8];
NSString *subtitles[8];
}
Should Be:
#interface ViewController : UIViewController
#property (strong, nonatomic) NSMutableArray *details;
#property (strong, nonatomic) NSMutableArray *subtitles;
You could declare it similar to the way you had it, but I believe this is the preferred current syntax. Others may correct me on this. Most important is that we declare NSMutableArray's as opposed to NSString's. You are doing C-style declarations, which will be a bit different with these. I chose NSMutableArray as opposed to NSArray because it looks like you want to be able to add objects at runtime.
And this:
self.label.text = subtitles[0];
should be:
if (!_subtitles) _subtitles = [NSMutableArray new];
[_subtitles insertObject:self.label.text atIndex:0];
This line:
if (!_subtitles) _subtitles = [NSMutableArray new];
Is just to make sure that our _subtitles dictionary exists, and if it does, we make sure that it isn't overwritten. the [NSMutableArray new] syntax is something that I personally like because it looks clean; however, many prefer [[NSMutableArray alloc]init]. Just so you're aware.

Related

Error when using setObject in NSMutableDictionary

I am getting the exception:
-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
The offending line is:
[delegate.sharedData.dictFaves setObject:#"test" forKey:#"4"];
Delegate is initialized thus in MyViewController.m:
delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
This is how my delegate is defined in AppDelegate.h:
#import "CommonData.h"
...
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
NSString *tempFave;
CommonData *sharedData;
}
#property (strong, nonatomic) NSString *tempFave;
#property (strong, nonatomic) CommonData *sharedData;
sharedData is initialized in AppDelegate.m thus:
#import "AppDelegate.h"
...
#implementation AppDelegate
#synthesize sharedData;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
sharedData = [[CommonData alloc] init];
return YES;
}
sharedData is defined in CommonData.h:
#interface CommonData : NSObject
{
NSMutableDictionary *dictAffirms;
NSMutableDictionary *dictFaves;
}
#property (nonatomic, copy) NSMutableDictionary *dictAffirms;
#property (nonatomic, copy) NSMutableDictionary *dictFaves;
shared data implementation file CommonData.m:
#import "CommonData.h"
...
#implementation CommonData
#synthesize dictAffirms;
#synthesize dictFaves;
#end
I have declared the members of CommonData to be Mutable. Apparently that is insufficient. What else must I do in order to write to the Dictionaries inside CommonData?
I have seen this error before when trying to write to a dictionary that is filled from a plist. If you use
yourMutableDictionary = [someDataSource objectForKey:#"someKey"];
your dictionary will be immutable, even if it is declared mutable. Use instead
yourMutableDictionary = [someDataSource mutableArrayValueForKey:#"someKey"];
and your problem will go away, assuming this is in fact your problem. It might be something like:
yourMutableDictionary = [[NSDictionary alloc] init];
or
yourMutableDictionary = [NSDictionary new];
and you just are accidentally creating immutable objects, which is pretty much the same problem as above, just different.
It would be nice to see the code used to initialize the NSMutableDictionaries.
Edit: Maybe try something like this, as I'm curious as to what the results would be. Instead of using:
[delegate.sharedData.dictFaves setObject:#"test" forKey:#"4"];
try
NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithDictionary:delegate.sharedData.dictFaves];
[dict setObject:#"test" forKey:#"4"];
delegate.sharedData.dictFaves = dict;
[dict release];
You've declared the dictFaves to be mutable, but that doesn't mean you actually stored a mutable object in there. Check your initializer. You'll probably have something like the following:
dictFaves = [[NSDictionary alloc] init];
If so, you need to change that to NSMutableDictionary instead.
Your problem is that your property setter for the dictionary is declared as copy. NSMutableDictionary's copy method returns an immutable NSDictionary (in general, copy almost always returns an immutable object). So assuming you're using the standard synthesized setter, any time you set that property, you're assigning the wrong type behind the scenes. It should probably be strong instead.

Problem with parsing strings

I am trying to put a line of dialog on each of a series of images.
To match the dialog line with the correct image, I end each line with a forward slash (/) followed by a number to identify the matching image. I then parse each line to get the dialog and then the reference number for the image.
It all works fine except that when I put the dialog line into a textView I get the whole line in the textView instead of the dialog part.
What is confusing is that the console seems to indicate that the parsing of the dialog line has been carried out correctly.
Here are the details of my coding:
#interface DialogSequence_1ViewController : UIViewController {
IBOutlet UIImageView *theImage;
IBOutlet UITextView *fullDialog;
IBOutlet UITextView *selectedDialog;
IBOutlet UIButton *test_1;
IBOutlet UIButton *test_2;
IBOutlet UIButton *test_3;
NSArray *arrayLines;
IBOutlet UISlider *readingSpeed;
NSArray *cartoonViews;
NSMutableString *dialog;
NSMutableArray *dialogLineSections;
int lNum;
}
#property (retain,nonatomic) UITextView *fullDialog;
#property (retain,nonatomic) UITextView *selectedDialog;
#property (retain,nonatomic) UIButton *test_1;
#property (retain,nonatomic) UIButton *test_2;
#property (retain,nonatomic) UIButton *test_3;
#property (retain,nonatomic) NSArray *arrayLines;
#property (retain,nonatomic) NSMutableString *dialog;
#property (retain,nonatomic) NSMutableArray *dialogLineSections;
#property (retain,nonatomic) UIImageView *theImage;
#property (retain,nonatomic) UISlider *readingSpeed;
-(IBAction)start:(id)sender;
-(IBAction)counter:(id)sender;
-(IBAction)runNextLine:(id)sender;
#end
#implementation DialogSequence_1ViewController
#synthesize fullDialog;
#synthesize selectedDialog;
#synthesize test_1;
#synthesize test_2;
#synthesize test_3;
#synthesize arrayLines;
#synthesize dialog;
#synthesize theImage;
#synthesize readingSpeed;
#synthesize dialogLineSections;
-(IBAction)runNextLine:(id)sender{
//Get dialog line to display from the arrayLines array
NSMutableString *dialogLineDetails;
dialogLineDetails =[arrayLines objectAtIndex:lNum];
NSLog(#"dialogLineDetails = %#",dialogLineDetails);
//Parse the dialog line
dialogLineSections = [dialogLineDetails componentsSeparatedByString: #"/"];
selectedDialog.text =[dialogLineSections objectAtIndex: 0];
NSLog(#"Dialog part of line = %#",[dialogLineSections objectAtIndex: 0]);
NSMutableString *imageBit;
imageBit = [dialogLineSections objectAtIndex: 1];
NSLog(#"Image code = %#",imageBit);
//Select right image
int im = [imageBit intValue];
NSLog(#"imageChoiceInteger = %i",im);
//------more code
}
I get a warning on the line:
dialogLineSections = [dialogLineDetails componentsSeparatedByString: #"/"];
warning: incompatible Objective-C types assigning 'struct NSArray *', expected 'struct NSMutableArray *'
I don't quite understand this and have tried to change the types but to no avail.
Would be grateful for some advice here.
The warning tells you exactly what the problem is. -componentsSeparatedByString: returns an immutable instance of NSArray, but you're assigning that result to a variable of type NSMutableArray. So you need to either change the variable to NSArray (in which case you can't modify it) or make a mutable copy of the components array (via -mutableCopy, which you must balance with -release or -autorelease to avoid memory leaks.)
The forward slash character is an escape character so you shouldn't use it as a delimiter. This can lead to random errors in string processing. Pick something else, preferably an arbitrary string like !123!
You are getting the warning because componentsSeparatedByString: returns a NSArray instead of an NSMutableArray and you are assigning the static array to a mutable array pointer. Instead use:
self.dialogSections=[NSMutableArray arrayWithArray:[dialogLineDetails componentsSeparatedByString: #"/"]];

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.

multiple objects for a single index in an NSArray

Is it possible to store multiple objects for a single index in an NSArray?
Sure there are many ways to do this with the most common being to assign a dictionary to each array element
Yes, you probably just want to have an NSArray of NSMutableArrays. You can then call something like this:
[[array objectAtIndex:2] addObject:obj];
or
[[array objectAtIndex:2] objectAtIndex:1];
I'm not sure how dynamic you want the multiple objects to be. How about creating a very simple class with properties of the multiple objects?
I was thinking about a struct but I don't think NSArrays like pointer objects.
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#interface myCompound : NSObject
{
}
#property (nonatomic,strong) NSColor* colour;
#property (nonatomic,strong) NSRegularExpression* expression;
#end
#implementation myCompound
#synthesize colour;
#synthesize expression;
#end
And use this as the element type for NSArray
NSArray<myCompound*>* myArray;

Objective-C dot syntax or property value?

I keep reading that dot syntax is possible but I keep getting errors that the struct does not contain members I am referencing. Perhaps its not the dot syntax so I have included details of what I am doing in hopes of a solution:
// MobRec.h - used as the objects in the MobInfo array
#import <Foundation/Foundation.h>
#interface MobRec : NSObject {
#public NSString *mName;
#public int mSpeed;
}
#property (nonatomic, retain) NSString *mName;
#property (nonatomic) int mSpeed;
// MobDefs.h - array of MobRecords
#interface Mobdefs : NSObject {
#public NSMutableArray *mobInfo;
}
#property(assign) NSMutableArray *mobInfo; // is this the right property?
-(void) initMobTable;
#end
// MobDefs.m
#import "Mobdefs.h"
#import "Mobrec.h"
#implementation Mobdefs
#synthesize mobInfo;
-(void) initMobTable
{
// if I use traditional method I get may not respond
[mobInfo objectAtIndex:0 setmName: #"doug"];
// if I use dot syntax I get struct has no member named mName
mobInfo[1].MName = #"eric";
}
// main.h
MobDefs *mobdef;
// main.m
mobdef = [[Mobdefs alloc] init];
[mobdef initMobTable];
although both methods should work I get erros on both. What am I doing wrong? My best thoughts have been that I am using the wrong #property but I think I have tried all. I am performing alloc in main. Ideally I would like to for this use dot syntax and cant see why its not allowing it.
A couple of things: (edit: original point #1 removed due to error)
Although the dot syntax is supported, the array index syntax for NSArray is not. Thus, your call to mobInfo[1] will not be the same as [mobInfo objectAtIndex:1]; Instead, mobInfo will be treated as a simple C-style array, and that call would be almost guaranteed to result in a crash.
You should not define variables in your header file as you do in main.h. The line MobDefs *mobdef; belongs somewhere in main.m.
edit: Here is how it should look:
MobRec.h
#interface MobRec : NSObject {
NSString *mName;
int mSpeed;
}
#property (nonatomic, retain) NSString *mName;
#property (nonatomic) int mSpeed;
MobRec.m
#implementation MobRec
#synthesize mName;
#synthesize mSpeed;
#end
MobDefs.h
#interface MobDefs : NSObject {
NSMutableArray *mobInfo;
}
#property(assign) NSMutableArray *mobInfo;
-(void) initMobTable;
#end
MobDefs.m
#import "MobDefs.h"
#import "MobRec.h"
#implementation MobDefs
#synthesize mobInfo;
-(void) initMobTable
{
// option 1:
[(MobRec*)[mobInfo objectAtIndex:0] setMName:#"doug"];
// option 2:
(MobRec*)[mobInfo objectAtIndex:0].mName = #"eric";
// option 3:
MobRec *mobRec = [mobInfo objectAtIndex:0];
mobRec.mName = #"eric";
}
main.m
MobDef *mobdef = [[MobDefs alloc] init];
[mobdef initMobTable];
...
[mobdef release]; // don't forget!
You need to either cast the object returned by -objectAtIndex:, or use a method call on it:
[[mobInfo objectAtIndex: 0] setMName: #"doug"];
or
((Mobrec *) [mobInfo objectAtIndex: 0]).MName = #"doug";
[mobInfo objectAtIndex:0 setmName: #"doug"];
There is no objectAtIndex:setmName method, so you're going to have to explain what you think this is even supposed to do.
mobInfo[1].MName = #"eric";
Use objectAtIndex to look something up in an NSArray object.