Objective C: Adding Images on different pages - objective-c

I am new to trying to create a book app adapting the page-based application of the new xcode just using the single view app, because it is quite confusing learning the template.
i found this code and i am trying to replace the HTML content of this work to UIImageView but i failed.
- (void) createContentPages
{
NSMutableArray *pageStrings = [[NSMutableArray alloc] init];
for (int i = 1; i < 11; i++)
{
NSString *contentString = [[NSString alloc]
initWithFormat:#"<html><head></head><body><h1>Chapter %d</h1><p>This is the page %d of content displayed using UIPageViewController in iOS 5.</p></body></html>", i, i];
[pageStrings addObject:contentString];
}
pageContent = [[NSArray alloc] initWithArray:pageStrings];
}
what i am trying to is to display different images per page.
here is what i did. (i know it is so wrong i just tried it)
- (void) createContentPages
{
NSMutableArray *pageStrings = [[NSMutableArray alloc] init];
for (int i = 1; i < 11; i++)
{
NSArray *photos = [[NSArray arrayWithObjects:
[UIImage imageNamed:#"p1.png"],
[UIImage imageNamed:#"p2.png"],
[UIImage imageNamed:#"p3.png"],
[UIImage imageNamed:#"p4.png"],
nil];
[pageStrings addObject:photos];
}
pageContent = [[NSArray alloc] initWithArray:pageStrings];
}
and it has UIWebView in each page. is it possible that if i replace it with UIImageView it will run?
Here's the rest of the code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self createContentPages];
NSDictionary *options =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin]
forKey: UIPageViewControllerOptionSpineLocationKey];
self.pageController = [[UIPageViewController alloc]
initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options: options];
pageController.dataSource = self;
[[pageController view] setFrame:[[self view] bounds]];
contentViewController *initialViewController =
[self viewControllerAtIndex:0];
NSArray *viewControllers =
[NSArray arrayWithObject:initialViewController];
[pageController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
[self addChildViewController:pageController];
[[self view] addSubview:[pageController view]];
[pageController didMoveToParentViewController:self];
}
- (contentViewController *)viewControllerAtIndex:(NSUInteger)index
{
// Return the data view controller for the given index.
if (([self.pageContent count] == 0) ||
(index >= [self.pageContent count])) {
return nil;
}
// Create a new view controller and pass suitable data.
contentViewController *dataViewController =
[[contentViewController alloc]
initWithNibName:#"contentViewController"
bundle:nil];
dataViewController.dataObject =
[self.pageContent objectAtIndex:index];
return dataViewController;
}
- (NSUInteger)indexOfViewController:(contentViewController *)viewController
{
return [self.pageContent indexOfObject:viewController.dataObject];
}
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerBeforeViewController:
(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:
(contentViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:
(contentViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageContent count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
on subclass
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[webView loadHTMLString:dataObject
baseURL:[NSURL URLWithString:#""]];
}

All time you may use the pictures inside HTML page using the HTML tag <IMG>. So, no the reason to use UIImageView.

Use your createContentPages() method with this one small change (UIImage alone don't represent anything you can put on a "view" Instead you need to use a UIImageView which holds UIImages):
- (void) createContentPages
{
NSMutableArray *pageStrings = [[NSMutableArray alloc] init];
for (int i = 1; i < 11; i++)
{
NSArray *photos = [[NSArray arrayWithObjects:
[[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"p1.png"] autorelease],
[[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"p2.png"] autorelease],
[[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"p3.png"] autorelease],
[[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"p4.png"] autorelease],
nil];
[pageStrings addObject:photos];
}
pageContent = [[NSArray alloc] initWithArray:pageStrings];
}
You can use the code from the main controller (the big block of code that you posted).
The only changes you'll need to make are in what you're calling the "subclass." (really it's the UIPageViewController that handles showing the actual pages).
In that UIPageViewController remove the "webView" (UIWebView). This is probably done in the .xib file (doesn't look like it's added in the code). Then make, viewWillAppear in the UIPageViewController look like this:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.view = dataObject;
}
That should do the trick. Basically, we are no longer using the UIWebView to show HTML data, and instead just adding the dataObject (a UIImageView) as a subview of the UIPageViewController. Hope this helps!

Related

How can I change this code so that it doesn't infringe MVC principles?

I am making a quiz app for chemistry reactions. The app gives the user a question, and the user types in the reactants and products in two separate textfields.
I have a data class, which contains all the possible quiz questions. Then, based on specific parameters, the data class selects a certain amount of questions from the pool of possible questions and shuffles them into an array, quizQuestions.
I also have a view controller, quizController. For each question, a new instance of quizController is loaded. The vc needs the data to know which question to display, what the correct answer is, etc.
This is my original solution to communicate between the data and the vc's.
I create an instance of the data class, data.
I create vc1 for the first question, and set data as a property of vc1, and set its tag as 1, so that it loads the 1st question from the data.
After the user answers the first question, I create a new view controller, vc2, in a method of vc1, make the tag 1 more than the last vc's so that the second question loads, and pass data from vc1's property to vc2's.
And then I repeat for the other questions.
However, this is not very good design, and I am looking for a better solution. I don't think I can use a class method because the data is supposed to contain a random set of questions. Below I have the code for the data class.
// the data class as it is now, designed for instance methods
- (id)init {
self = [super init];
if (self) {
//Questions of the same type belong to a "ROW" (Reaction of Week)
//individual questions
// Items in array: (1)Question, (2)Reactants, (3)Products, (4)Elements for keyboard
NSArray *R1Q1 = [[NSArray alloc] initWithObjects:#"Methanol is burned completely in air", #"2CH₃OH(l) + 3O₂(g)", #"2CO₂(g) + 4H₂O", #"C,H,O", nil];
NSArray *R1Q2 = [[NSArray alloc] initWithObjects:#"Ammonia is burned in excess oxygen gas", #"4NH₃(g) + 7H₂O(l)", #"4NO₂(g) + 6H₂O(l)", #"N,H,O", nil];
NSArray *R1Q3 = [[NSArray alloc] initWithObjects:#"Hydrogen sulfide gas is burned in excess oxygen gas", #"2H₂S(g) + 3O₂(g)", #"CO₂(g) + 2SO₂(g)", #"H,S,O", nil];
NSArray *R2Q1 = [[NSArray alloc] initWithObjects:#"Solid potassium is added to a flask of oxygen gas", #"K(s) + O₂(g)", #"KO₂(s)", #"K,O", nil];
NSArray *R2Q2 = [[NSArray alloc] initWithObjects:#"Sodium metal is dropped into a flask of pure water", #"2Na(s) + H₂O(l)", #"2Na⁺(aq) + 2OH⁻(aq) + H₂(g)", #"Na,H,O", nil];
NSArray *R2Q3 = [[NSArray alloc] initWithObjects:#"A piece of lithium is heated strongly in oxygen", #"4Li(s) + O₂(g)", #"2Li₂O(s)", #"Li,O", nil];
NSArray *R3Q1 = [[NSArray alloc] initWithObjects:#"Solutions of potassium chloride and silver nitrate are mixed", #"Ag⁺(aq) + Cl⁻(aq)", #"AgCl(s)", #"K,Cl,Ag,N,O", nil];
NSArray *R3Q2 = [[NSArray alloc] initWithObjects:#"Solutions of iron(III) nitrate and sodium hydroxide are mixed", #"Fe³⁺(aq) + 3OH⁻(aq)", #"Fe(OH)₃(s)", #"Fe,N,O,Na,H", nil];
NSArray *R3Q3 = [[NSArray alloc] initWithObjects:#"Solutions of nickel iodide and barium hydroxide are mixed", #"Ni²⁺(aq) + 2OH⁻(aq)", #"Ni(OH)₂(s)", #"Ni,I,Ba,OH", nil];
// add rest
//organize questions into groups
row1 = [[NSArray alloc] initWithObjects:R1Q1, R1Q2, R1Q3, nil];
row2 = [[NSArray alloc] initWithObjects:R2Q1, R2Q2, R2Q3, nil];
row3 = [[NSArray alloc] initWithObjects:R3Q1, R3Q2, R3Q3, nil];
//add rest
// array containing all questions
allRows = [[NSMutableArray alloc] initWithObjects:row1, row2, row3, nil];
//in a real situation, needs to be given to class dynamically
self.maxRowNumber = 3;
self.questionsPerRow = 2;
}
return self;
}
- (void)selectQuestions {
self.quizQuestions = [[NSMutableArray alloc] init];
for (int j = 0; j<self.maxRowNumber; j++) {
//shuffle each row
NSMutableArray *row = [NSMutableArray arrayWithArray:[allRows objectAtIndex:j]];
[row shuffle];
//add questions from each row
for (int k = 0; k<self.questionsPerRow; k++)
[quizQuestions addObject:[row objectAtIndex:k]];
}
[quizQuestions shuffle];
}
View Controller code excerpts
# pragma mark Cell Setup
//1st cell in tableview
- (void) setUpEquationCell: (UITableView *) tableView {
equationCell = (EquationCell *) [tableView dequeueReusableCellWithIdentifier:#"equationCell"];
if (equationCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"EquationCell" owner:self options:nil];
equationCell = (EquationCell*) [nib objectAtIndex:0];
[equationCell.leftButton addTarget:self action:#selector(addDissociateCell) forControlEvents:UIControlEventTouchUpInside];
[equationCell.rightButton addTarget:self action:#selector(addBalanceCell) forControlEvents:UIControlEventTouchUpInside];
}
}
- (void) setUpBalanceCell: (UITableView *) tableView {
//2nd cell in tableview
balanceCell = (BalanceCell *) [tableView dequeueReusableCellWithIdentifier:#"balanceCell"];
if (balanceCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"BalanceCell" owner:self options:nil];
balanceCell = (BalanceCell*) [nib objectAtIndex:0];
// stores data from equation cell into model
for (FormulaLabel *label in equationCell.leftView.equationOrder)
[leftData.equation addObject:label.text];
for (FormulaLabel *label in equationCell.rightView.equationOrder)
[rightData.equation addObject:label.text];
[leftData setUpBalancedEquation];
[rightData setUpBalancedEquation];
[self setUpView:balanceCell.leftView fromArray:leftData.equation toArray:leftBalanceItems];
[self setUpView:balanceCell.rightView fromArray:rightData.equation toArray:rightBalanceItems];
[self addBalanceTapMethodInArray:leftBalanceItems Data:leftData];
[self addBalanceTapMethodInArray:rightBalanceItems Data:rightData];
}
}
- (void) setUpDissociateCell: (UITableView *) tableView {
dissCell = (DissociateCell *) [tableView dequeueReusableCellWithIdentifier:#"dissCell"];
if (dissCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"DissociateCell" owner:self options:nil];
dissCell = (DissociateCell*) [nib objectAtIndex:0];
leftData.disEquation = [[NSMutableArray alloc] init];
rightData.disEquation = [[NSMutableArray alloc] init];
// stores data from equation cell into model
for (FormulaLabel *label in equationCell.leftView.equationOrder)
[leftData.disEquation addObject:label.text];
for (FormulaLabel *label in equationCell.rightView.equationOrder)
[rightData.disEquation addObject:label.text];
[self setUpView:dissCell.leftView fromArray:leftData.disEquation toArray:leftDisItems];
[self setUpView:dissCell.rightView fromArray:rightData.disEquation toArray:rightDisItems];
[self addDissTapToArray:leftDisItems fromData:leftData inView:dissCell.leftView];
[self addDissTapToArray:rightDisItems fromData:rightData inView:dissCell.rightView];
[dissCell.dissociateButton addTarget:self action:#selector(dissociate) forControlEvents:UIControlEventTouchUpInside];
}
[dissCell.rightButton addTarget:self action:#selector(addBalanceCell) forControlEvents:UIControlEventTouchUpInside];
}
- (void)addDissociateCell {
[cellOrder addObject:#"dissociateCell"];
[table reloadData];
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:0 inSection:([cellOrder count]-1)];
[table scrollToRowAtIndexPath:myIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (void) addDissTapToArray:(NSMutableArray*)viewOrder fromData:(EquationData*)data inView:(UIView*)view {
NSString *leftOrRight;
if (view == dissCell.leftView)
leftOrRight = #"left";
else
leftOrRight = #"right";
for (int j=0; j < [viewOrder count]; j++) {
if (j%2==0) {
UIView *formulaView = [viewOrder objectAtIndex:j];
//dissociate method
FalseTarget *target = [[FalseTarget alloc] initWithVC:self leftOrRightView:leftOrRight];
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:target action:#selector(dissTap:)];
[formulaView addGestureRecognizer:tap];
// cancelling method
FalseTarget *target2 = [[FalseTarget alloc] initWithVC:self Data:data ViewList:viewOrder view:view];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:target2 action:#selector(dissLongTap:)];
[formulaView addGestureRecognizer:longPress];
}
}
}
- (void)addCompoundToLabel:(UIGestureRecognizer *)recognizer leftOrRight:(NSString*)leftRight{
if( [recognizer state] == UIGestureRecognizerStateEnded ) {
FormulaLabel* label = (FormulaLabel*)[recognizer view];
dissIndex = label.tag;
dissCell.unDissociated.text = label.text;
currentDissCellView = leftRight;
}
}
- (void)dissociate {
EquationData *data;
NSMutableArray *viewOrder;
UIView *view;
if ([currentDissCellView isEqualToString:#"left"]) {
data = leftData;
viewOrder = leftDisItems;
view = dissCell.leftView;
}
else {
data = rightData;
viewOrder = rightDisItems;
view = dissCell.rightView;
}
FormulaLabel *c1 = [dissCell.leftTextField.equationOrder objectAtIndex:0];
FormulaLabel *c2 = [dissCell.rightTextField.equationOrder objectAtIndex:0];
[data updateDisEquationAtIndex:dissIndex withCompound1:c1.text Compound2:c2.text];
for (UIView *view in viewOrder)
[view removeFromSuperview];
[viewOrder removeAllObjects];
[self setUpView:view fromArray:data.disEquation toArray:viewOrder];
[self addDissTapToArray:viewOrder fromData:data inView:view];
}
- (void) cancelIons:(id)sender fromData:(EquationData *)data inView:(UIView *)view withViewList:(NSMutableArray *)viewlist {
if( [sender state] == UIGestureRecognizerStateEnded ) {
FormulaLabel* label = (FormulaLabel*)[sender view];
int index = label.tag;
[data.disEquation removeObjectAtIndex:index];
for (UIView *formulaView in viewlist)
[formulaView removeFromSuperview];
[viewlist removeAllObjects];
[self setUpView:view fromArray:data.disEquation toArray:viewlist];
[self addDissTapToArray:viewlist fromData:data inView:view];
}
}
- (void)addBalanceCell {
[cellOrder addObject:#"balanceCell"];
[table reloadData];
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:0 inSection:([cellOrder count]-1)];
[table scrollToRowAtIndexPath:myIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
leftBalanceItems = [[NSMutableArray alloc] init];
rightBalanceItems = [[NSMutableArray alloc] init];
}
- (void) addBalanceTapMethodInArray:(NSMutableArray *)balanceItems Data:(EquationData *)data {
FalseTarget *target = [[FalseTarget alloc] initWithVC:self Data:data ViewList:balanceItems view:nil];
for (UIView *view in balanceItems) {
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:target action:#selector(tap:)];
[view addGestureRecognizer:tap];
}
}
- (void)updateBalanceLabelofSender:(UIGestureRecognizer*)sender fromData:(EquationData *)data inArray:(NSMutableArray *)balanceItems {
FormulaLabel* label = (FormulaLabel*)[sender view];
int oldWidth = label.frame.size.width;
label.text = [data updateBalancedatIndex:label.tag];
[label sizeToFit];
int newWidth = label.frame.size.width;
int difference = newWidth - oldWidth;
int labelIndex = label.tag * 2;
for (int j = 0; j<[balanceItems count]; j++) {
// adjusts coordinate of all views to the right of tapped item
if (j > labelIndex){
UIView *item = [balanceItems objectAtIndex:j];
item.frame = CGRectMake(item.frame.origin.x + difference, item.frame.origin.y, item.frame.size.width, item.frame.size.height);
}
}
}
- (void)setUpView:(UIView *)view fromArray:(NSMutableArray *)equationData toArray:(NSMutableArray *)balanceItems {
int labelCount = 0; //label #
int startingPoint = 5; //x vaiue where first label starts
for (NSString *equationText in equationData) {
//add text
FormulaLabel *tempLabel = [[FormulaLabel alloc] initWithFrame:CGRectMake(startingPoint, 2, 10, 22)];
tempLabel.text = equationText;
[tempLabel sizeToFit];
[view addSubview:tempLabel];
tempLabel.tag = labelCount;
[balanceItems addObject:tempLabel];
//set location of '+'
startingPoint = tempLabel.frame.origin.x + tempLabel.frame.size.width + 3;
if (labelCount != [equationData count]-1) { //not the last label
UILabel *plus = [[[UILabel alloc] initWithFrame:CGRectMake(startingPoint, 5, 10, 10)]autorelease];
plus.text = #"+";
plus.font = [UIFont systemFontOfSize:13];
[plus sizeToFit];
[view addSubview:plus];
startingPoint = plus.frame.origin.x + plus.frame.size.width + 3;
[balanceItems addObject:plus];
}
labelCount ++;
[tempLabel release];
}
}
Why can't you use one view controller class with a question-property where you overload the property's setter method to update the UI to the new data:
in QuestionViewController.h file:
#property (retain, nonatomic) Question* myQuestionData;
in QuestionViewController.m
-(void) setMyQuestionData:(Question*)newData {
[myQuestionData autorelease];
myQuestionData = [newData retain];
[self updateUIElements];
}
I wouldn't do like that, because you are forcing the UIViewController to know about the data model (while making it it's property). What I would do, would be a class and using class methods (and not object methods) would create the data source. You would still have to hold the data in the UIViewController somehow, but I think a NSArray or a NSDictionary would be good enough:
-(void)viewDidLoad{
[superViewDidLoad];
myArray = [MyModel createDataSourceForTag:myTag];
}
I guess here you should go with Model structure.
1. Model: Model represents to entity. Here in your case, there i can create two entities Round, Question
#interface Round: NSObject {
NSUInteger *roundId; // 1, 2 = if it is required to check then this mi
NSArray *questions; // Array that contains objects for Question entity
}
#interface Question:NSObject {
NSString *questionText;
NSString *options1Text;
NSString *options2Text;
NSString *options3Text;
}
#interface DataManager:NSObject {
NSArray *rounds; // Array that contains object for Round entity
}
+(void)sharedInstance;
2. DataManger: DataManager will manage your entity objects. This data manager will be an sharedInstance class. So while initializing manager, entities will be created and data will be inserted.
3. ViewController: Now in view controller you can directly use sharedInstace, like this:
[[DataManager sharedInstance] rounds]
You can easily get code for creating sharedInstance class.
Now you can use this rounds anywhere in the entire application.
So it will be quiet easy to access. For example, if you require 1st round 2nd question 3rd option then, write code for same way
Round 1
Round *r = [[[DataManager sharedInstance] rounds] objectAtIndex:0];
Question 2
Question *q = [[r questions] objectAtIndex:1];
Question Text and Option 3
NSLog(#"questionText : %# 3rd Option: %#", q.questionText, q.option3Text)
Enjoy Coding :)

Multiple UIPickers to show in action sheet

in one of my view controllers I want to use multiple pickers.
Header file:
#interface MyTableController : TTTableViewController <UIActionSheetDelegate, UIPickerViewDataSource, UIPickerViewDelegate>{
IBOutlet UIPickerView *picker1;
IBOutlet UIPickerView *picker2;
NSMutableArray *list1;
NSMutableArray *list2;
}
#property(nonatomic,retain) UIPickerView *picker1, *picker2;
-(IBAction)togglePickerView1;
-(IBAction)togglePickerView2;
#end
Implementation file:
#implementation MyTableController
#synthesize picker1, picker2;
int row_index1 = 0;
int row_index2 = 0;
- (void)locationPicker:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
if([pickerView isEqual: picker1]){
row_index1 = row;
}
if([pickerView isEqual: picker2]){
row_index2 = row;
}
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
if([pickerView isEqual: picker1]){
return 1;
}
if([pickerView isEqual: picker2]){
return 1;
}
return 0;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
if([pickerView isEqual: picker1]){
return [list1 count];
}
if([pickerView isEqual: picker2]){
return [list2 count];
}
return 0;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent: (NSInteger)component{
return [list objectAtIndex:row];
if([pickerView isEqual: picker1]){
return [list1 objectAtIndex:row];
}
if([pickerView isEqual: picker2]){
return [list2 objectAtIndex:row];
}
return nil;
}
-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
}
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
if (actionSheet.tag == 111) {
picker1 = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 40, 320, 216)];
picker1.showsSelectionIndicator = YES;
picker1.dataSource = self;
picker1.delegate = self;
//Add picker to action sheet
[actionSheet addSubview:picker1];
[picker1 release];
}else if(actionSheet.tag == 222){
picker2 = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 40, 320, 216)];
picker2.showsSelectionIndicator = YES;
picker2.dataSource = self;
picker2.delegate = self;
//Add picker to action sheet
[actionSheet addSubview:picker2];
[picker2 release];
}
//Gets an array af all of the subviews of our actionSheet
NSArray *subviews = [actionSheet subviews];
[[subviews objectAtIndex:1] setFrame:CGRectMake(20, 266, 280, 46)];
[[subviews objectAtIndex:2] setFrame:CGRectMake(20, 317, 280, 46)];
}
-(IBAction)togglePickerView1{
UIActionSheet *asheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedString(#"FLT", nil) delegate:self cancelButtonTitle:NSLocalizedString(#"CANCEL", nil) destructiveButtonTitle:nil otherButtonTitles:NSLocalizedString(#"PICK", nil), nil];
[asheet setTag:111];
[asheet showInView:[self.view superview]]; //note: in most cases this would be just self.view, but because I was doing this in a tabBar Application, I use the superview.
[asheet setFrame:CGRectMake(0, 117, 320, 383)];
[asheet release];
}
-(IBAction)togglePickerView2{
//...
[asheet setTag:222];
//...
}
- (void)loadView {
[super loadView];
}
-(void)viewDidLoad{
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithTitle:#"Button1" style:UIBarButtonItemStyleBordered target:self action:#selector(togglePickerView1)];
UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:#"Button2" style:UIBarButtonItemStyleBordered target:self action:#selector(togglePickerView2)];
NSArray *myToolbarItems = [[NSArray alloc] initWithObjects: item1, item2, nil];
[self setToolbarItems: myToolbarItems];
[myToolbarItems release];
list1 = [[NSMutableArray alloc] init];
[list1 addObject:#"--"];
[list1 addObject:#"Test1"];
list2 = [[NSMutableArray alloc] init];
[list2 addObject:#"--"];
[list2 addObject:#"Test2"];
}
#end
My problem is that no matter which button I hit, it is always the picker1 that is triggered. Any ideas where the problem is?
You are successfully creating two different pickers, and showing the correct one each time.
The problem is, each picker has the same data in it.
The first line in your data source titleForRow... method is this:
return [list objectAtIndex:row];
This ends execution of your data source method by returning a value, so both pickers will always show the same data, regardless of the rest of your code. list isn't declared anywhere in your code above so I'm not sure what you are actually seeing on the screen.
I have built a sample project using your code above and confirmed that this is the issue. Removing that line gives you two different pickers, with the different content in each one.

TTLauncherItem: change badge immediately (or: how to refresh TTLauncherView)

I have a TTLauncherView with some TTLauncherItems. These show badges, representing messages from the network. I set the badges in viewWillAppear:, so if I switch to another view and then return, the correct badges are shown. But I want to update the badges as soon a message comes in.
Calling setNeedsDisplay on TTLauncherView doesn't help?
How can I refresh the TTLauncherView?
in my MessageReceiver class I do this:
TTNavigator* navigator = [TTNavigator navigator];
[(OverviewController *)[navigator viewControllerForURL:#"tt://launcher"] reloadLauncherView] ;
My TTViewController-derived OverviewController
#implementation OverviewController
- (id)init {
if (self = [super init]) {
self.title = OverviewTitle;
}
return self;
}
- (void)dealloc {
[items release];
[overView release];
[super dealloc];
}
-(void)viewDidLoad
{
[super viewDidLoad];
overView = [[TTLauncherView alloc] initWithFrame:self.view.bounds];
overView.backgroundColor = [UIColor whiteColor];
overView.delegate = self;
overView.columnCount = 4;
items = [[NSMutableArray alloc] init];
for(int i = 1; i <= NumberOfBars; ++i){
NSString *barID = [NSString stringWithFormat:NameFormat, IDPrefix, i];
TTLauncherItem *item = [[[TTLauncherItem alloc] initWithTitle:barID
image:LogoPath
URL:[NSString stringWithFormat:#"tt://item/%d", i]
canDelete:NO] autorelease];
[barItems addObject: item];
}
overView.pages = [NSArray arrayWithObject:items];
[self.view addSubview:overView];
}
-(void)viewWillAppear:(BOOL)animated
{
for(int i = 0; i <[barItems count]; i++){
TTLauncherItem *item = [items objectAtIndex:i];
NSString *barID = [NSString stringWithFormat:NameFormat, IDPrefix, i+1];
P1LOrderDispatcher *dispatcher = [OrderDispatcher sharedInstance];
P1LBarInbox *barInbox = [dispatcher.barInboxMap objectForKey:barID];
item.badgeNumber = [[barInbox ordersWithState:OrderState_New]count];
}
[super viewWillAppear:animated];
}
- (void)launcherView:(TTLauncherView*)launcher didSelectItem:(TTLauncherItem*)item
{
TTDPRINT(#"%#", item);
TTNavigator *navigator = [TTNavigator navigator];
[navigator openURLAction:[TTURLAction actionWithURLPath:item.URL]];
}
-(void)reloadLauncherView
{
[overView setNeedsDisplay];//This doesn't work
}
#end
I register my Controller with the LauncherView at the AppDelegate. In my messaging class I call [appDelegate reloadLauncherView]; that again will call this
-(void)reloadLauncherView
{
[self viewWillAppear:NO ];
}
on the Controller that contains the LauncherView.
I was having a very similar problem today, (modifying a TTLauncherItem, and not seeing my changes directly) and was able to solve it by making a call to [myLauncherView layoutSubviews]; BEFORE I modified the TTLauncherItem. I actually tracked it down in the code, and this was because layoutSubviews will re-create the LauncherView's _buttons array (which is what needed to happen, in my case).

Why is my UIPickerView not animating like it should be?

so this is basically like a slot machine type thing, very basic, but the problem Im having is that when you click the spin button the movement of the components is not animated, even though i have sent the animated argument a YES BOOL. I have no idea what I am doing wrong, any help would be appreciated.
Nick
ps download the entire project here: http://files.me.com/knyck2/dcca9y
//
// CustomPickerViewController.m
// Pickers
//
// Created by Nicholas Iannone on 1/29/10.
// Copyright 2010 Apple Inc. All rights reserved.
//
#import "CustomPickerViewController.h"
#implementation CustomPickerViewController
#synthesize column1, column2, column3, column4, column5, picker, winLabel;
-(IBAction) spin : (id) sender {
NSLog(#"even got here");
BOOL win = NO;
int numInRow = 1;
int lastVal = -1;
for (int i = 0; 1 < 5; i++) {
int newValue = random() % [self.column1 count];
if (newValue == lastVal) {
NSLog(#"even got here");
numInRow++;
}
else
numInRow = 1;
lastVal = newValue;
[picker selectRow:newValue inComponent:i animated:YES];
[picker reloadComponent:i];
if (numInRow >= 3)
win = YES;
NSLog(#"even got here");
}
if (win)
winLabel.text = #"winner!";
else {
winLabel.text = #"";
NSLog(#"even got here");
}
}
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
UIImage *seven = [UIImage imageNamed:#"seven.png"];
UIImage *bar = [UIImage imageNamed:#"bar.png"];
UIImage *crown = [UIImage imageNamed:#"crown.png"];
UIImage *cherry = [UIImage imageNamed:#"cherry.png"];
UIImage *lemon = [UIImage imageNamed:#"lemon.png"];
UIImage *apple = [UIImage imageNamed:#"apple.png"];
for (int i = 1; i <= 5 ; i++) {
UIImageView *sevenView = [[UIImageView alloc] initWithImage: seven];
UIImageView *barView = [[UIImageView alloc] initWithImage: bar];
UIImageView *crownView = [[UIImageView alloc] initWithImage: crown];
UIImageView *cherryView = [[UIImageView alloc] initWithImage: cherry];
UIImageView *lemonView = [[UIImageView alloc] initWithImage: lemon];
UIImageView *appleView = [[UIImageView alloc] initWithImage: apple];
NSArray *imageViewArray = [[NSArray alloc] initWithObjects: sevenView, barView, crownView, cherryView, lemonView, appleView, nil];
NSString *fieldName =[[NSString alloc] initWithFormat:#"column%d", i];
[self setValue:imageViewArray forKey:fieldName];
[fieldName release];
[imageViewArray release];
[sevenView release];
[crownView release];
[barView release];
[cherryView release];
[lemonView release];
[appleView release];
}
srandom(time(NULL));
[super viewDidLoad];
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[picker release];
[winLabel release];
[column1 release];
[column2 release];
[column3 release];
[column4 release];
[column5 release];
[super dealloc];
}
#pragma mark -
#pragma mark Picker Data Source Methods
-(NSInteger) numberOfComponentsInPickerView: (UIPickerView *) pickerView {
return 5;
}
-(NSInteger) pickerView: (UIPickerView *) pickerView numberOfRowsInComponent: (NSInteger) component {
return [self.column1 count];
}
#pragma mark Picker Delegate Methods
-(UIView *) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent: (NSInteger) component reusingView : (UIView *)view {
NSString *arrayName = [[NSString alloc] initWithFormat:#"column%d", component + 1];
NSArray *array = [self valueForKey:arrayName];
NSLog(#"got here yo");
return [array objectAtIndex: row];
NSLog(#"holyshit");
}
#end
I went back and compared my code to the book that this project is listed in and I noticed that my code would perform as expected (with animation) if I were to build into a 3.1.2 sdk and iphone sim. So something in the new xcode is skanking the animation, at least that is the way it appears.
It's probably not animating because you do [picker reloadComponent:i] right after selecting a row with animation. Reloading probably causes any animation to stop, and shouldn't be necessary since you're not actually changing the contents of the picker.

pickerview app crashing due to NSRangeException NSCFArray objectAtIndex: index (5)...beyond bounds (5)

Once again working through beginning iphone development and I am putting together a bunch of UIPicker type apps, the last one of which is a slot machine type of game, super simple. Anyway I am not really understanding why this error is coming up. to my understanding the picker view is asking its delegate for an object in the array that is past the range available to that array.
That being said I have no idea why it is doing this or how to fix it, any help would be appreciated, heres the code from the particular .m file( get the full project here: http://files.me.com/knyck2/89q3w3 ):
//
// CustomPickerViewController.m
// Pickers
//
// Created by Nicholas Iannone on 1/29/10.
// Copyright 2010 Apple Inc. All rights reserved.
//
#import "CustomPickerViewController.h"
#implementation CustomPickerViewController
#synthesize column1, column2, column3, column4, column5, picker, winLabel;
-(IBAction) spin : (id) sender {
NSLog(#"even got here");
BOOL win = NO;
int numInRow = 1;
int lastVal = -1;
for (int i = 0; 1 < 5; i++) {
int newValue = random() % [self.column1 count];
if (newValue == lastVal) {
NSLog(#"even got here");
numInRow++;
}
else
numInRow = 1;
lastVal = newValue;
[picker selectRow:newValue inComponent:i animated:YES];
[picker reloadComponent:i];
if (numInRow >= 3)
win = YES;
NSLog(#"even got here");
}
if (win)
winLabel.text = #"winner!";
else {
winLabel.text = #"";
NSLog(#"even got here");
}
}
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
UIImage *seven = [UIImage imageNamed:#"seven.png"];
UIImage *bar = [UIImage imageNamed:#"bar.png"];
UIImage *crown = [UIImage imageNamed:#"crown.png"];
UIImage *cherry = [UIImage imageNamed:#"cherry.png"];
UIImage *lemon = [UIImage imageNamed:#"lemon.png"];
UIImage *apple = [UIImage imageNamed:#"apple.png"];
for (int i = 1; i <= 5 ; i++) {
UIImageView *sevenView = [[UIImageView alloc] initWithImage: seven];
UIImageView *barView = [[UIImageView alloc] initWithImage: bar];
UIImageView *crownView = [[UIImageView alloc] initWithImage: crown];
UIImageView *cherryView = [[UIImageView alloc] initWithImage: cherry];
UIImageView *lemonView = [[UIImageView alloc] initWithImage: lemon];
UIImageView *appleView = [[UIImageView alloc] initWithImage: apple];
NSArray *imageViewArray = [[NSArray alloc] initWithObjects: sevenView, barView, crownView, cherryView, lemonView, appleView, nil];
NSString *fieldName =[[NSString alloc] initWithFormat:#"column%d", i];
[self setValue:imageViewArray forKey:fieldName];
[fieldName release];
[imageViewArray release];
[sevenView release];
[crownView release];
[barView release];
[cherryView release];
[lemonView release];
[appleView release];
}
srandom(time(NULL));
[super viewDidLoad];
}
/*
// Override to allow orientations other than the default portrait orientation.
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[picker release];
[winLabel release];
[column1 release];
[column2 release];
[column3 release];
[column4 release];
[column5 release];
[super dealloc];
}
#pragma mark -
#pragma mark Picker Data Source Methods
-(NSInteger) numberOfComponentsInPickerView: (UIPickerView *) pickerView {
return 5;
}
-(NSInteger) pickerView: (UIPickerView *) pickerView numberOfRowsInComponent: (NSInteger) component {
return [self.column1 count];
}
#pragma mark Picker Delegate Methods
-(UIView *) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent: (NSInteger) component reusingView : (UIView *)view {
NSString *arrayName = [[NSString alloc] initWithFormat:#"column%d", component + 1];
NSArray *array = [self valueForKey:arrayName];
NSLog(#"got here yo");
return [array objectAtIndex: row];
NSLog(#"holyshit");
}
#end
The reason why it's breaking is this loop. Take a look at your for loop condition:
1 < 5. Yes, 1 is always less than 5. This means that you have an infinite loop. I'm sure you meant i < 5.
for (int i = 0; 1 < 5; i++) {
int newValue = random() % [self.column1 count];
if (newValue == lastVal) {
NSLog(#"even got here");
numInRow++;
}
else
numInRow = 1;
lastVal = newValue;
[picker selectRow:newValue inComponent:i animated:YES];
[picker reloadComponent:i];
if (numInRow >= 3)
win = YES;
NSLog(#"even got here");
}
You're testing if 1 < 5, which is always true. You want i < 5.