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.
Related
I am trying to implement example as shown on developer.apple.com
Everything works but selectedWeapon does not change.
Q1: I have no idea what I forgot so the selection would work correctly
Q2: According to Apple "the example requires no actual code to set up the user interface". I am filling objects from code. Is there any way to add objects into arrayController in XIB?
#implementation Combatant
- (instancetype)initWithName:(NSString *)aName
{
self = [super init];
if (self) {
_weapons = #[#"Dagger", #"Sword", #"Pike"];
_name = aName;
_selectedWeapon = [_weapons firstObject];
}
return self;
}
#end
#interface Combatant : NSObject
#property (nonatomic, strong) NSString *name;
#property id selectedWeapon;
#property NSArray *weapons;
- (instancetype)initWithName:(NSString *)aName;
#end
Repository: https://github.com/xhruso00/moderatelyComplexBindings
Q1: The selection index of NSPopupButton wasn't linked to arrayController. Without it the arrayController did not know which option is selected.
Q2: Impossible. Apple talks about the glue code.
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.
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]);
}
}
I want to store a list of data records in a NSMutableArray for use in a UITableView. In other languages I would have used a simple 'type' structure to define the record structure but I understand the way to do this in Obj-C is to define a new class. I've done this as follows :
#interface CustSuppListItem : NSObject
#property (nonatomic, copy, readwrite) NSString *acCode;
#property (nonatomic, copy, readwrite) NSString *acCompany;
#property (nonatomic, copy, readwrite) NSString *acContact;
#property (nonatomic, assign, readwrite) double osBalBase;
#property (nonatomic, assign, readwrite) unsigned int acAccStatus;
#end
#implementation CustSuppListItem
#synthesize acCode, acCompany, acContact, osBalBase, acAccStatus;
#end
In the viewDidLoad of my UITableViewController I instantiate the array :
tableListDataArray = [[NSMutableArray alloc] init];
Once I have retrieved my data, I add it to the array as follows :
CustSuppListItem *custSuppItem = [[CustSuppListItem alloc] init];
[custSuppItem setAcCode:[jsonCustSuppRecord getStringForKey:#"acCode"]];
[custSuppItem setAcCompany:[jsonCustSuppRecord getStringForKey:#"acCompany"]];
[custSuppItem setAcContact:[jsonCustSuppRecord getStringForKey:#"acContact"]];
[custSuppItem setOsBalBase:[jsonCustSuppRecord getDoubleForKey:#"osBalBase"]];
[custSuppItem setAcAccStatus:[jsonCustSuppRecord getIntForKey:#"acAccStatus"]];
[tableListDataArray addObject:custSuppItem];
[custSuppItem release];
In my table cellForRowAtIndexPath method, I retrieve the data for the current cell as follows:
CustSuppListItem *listDataRecord = [tableListDataArray objectAtIndex:indexPath.row];
[cell.lblCompanyName setText:listDataRecord.acCompany]; // EXC_BAD_ACCESS here
[cell.lblAcCodeContact setText:[NSString stringWithFormat:#"%#, %#",
listDataRecord.acCode, listDataRecord.acContact]];
[cell.lblBalance setText:[Utils fmtNumber:listDataRecord.osBalBase withDecPlaces:2]];
[cell.lblStatus setText:[Utils exchAccStatusDesc:listDataRecord.acAccStatus]];
return cell;
In the dealloc method for the view controller I release the NSMutableArray :
[tableListDataArray release];
I'm very new to Obj-C so it would be great if somebody could confirm everything I've done so far makes sense and is in order. I am getting an intermittent EXC_BAD_ACCESS error when trying to read the acCompany property (see comment next to line) so something must not be right.
Any help appreciated,
Jonathan
All your code looks reasonable and correct to me at first glance.
A few things that I would look at are:
Confirm that cell definitely has a property lblCompanyName. If you're trying to assign to a property that doesn't exist then you will get this type of error. Have you defined a custom cell object type?
Confirm that it is always the acCompany property that is causing the EXC_BAD_ACCESS, and not just any property on the object. One way to do this would be to change the ordering of the lines in the cellForRowAtIndexPath method.
Confirm that the listDataRecord that's causing the crash is getting populated correctly in the first place. In other words, confirm that your jsonCustSuppRecord is always valid. What does jsonCustSuppRecord getStringForKey: return if the key doesn't exist in the jsonCustSuppRecord?
Set a breakpoint at this line: [tableListDataArray addObject:custSuppItem]; and examine the contents of the custSuppItem each time (this is an extension of point 3. above)
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: #"/"]];