I am calling the Contact Picker View like so:
- (void)openContacts {
CNContactPickerViewController *picker = [[CNContactPickerViewController alloc] init];
picker.delegate = self;
picker.displayedPropertyKeys = #[CNContactGivenNameKey];
[self presentViewController:picker animated:YES completion:nil];
}
And I am handling the selections with this delegate method:
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContacts:(NSArray<CNContact *> *)contacts {
for (CNContact *contact in contacts) {
NSLog(#"%#",contact);
NSString *phone;
NSString *mobilePhone;
for (CNLabeledValue *label in contact.phoneNumbers) {
if ([label.label isEqualToString:CNLabelPhoneNumberMobile] || [label.label isEqualToString:CNLabelPhoneNumberiPhone]) {
mobilePhone = [label.value stringValue];
} else if ([label.label isEqualToString:CNLabelPhoneNumberMain]) {
phone = [label.value stringValue];
}
}
}
}
The NSLog outputs the following for contact: <CNContact: 0x78e56e50: identifier=1861C9BD-143B-4E93-8475-F9079F5D6192, givenName=Kate, familyName=Bell, organizationName=Creative Consulting, phoneNumbers=(not fetched), emailAddresses=(not fetched), postalAddresses=(not fetched)>
This only occurs on simulator and iOS9 iPad. I don't get an error with my iOS10 iPhone.
You should first ask permission for this. Then you can show picker.
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error)
{
CNContactPickerViewController *picker = [[CNContactPickerViewController alloc] init];
picker.delegate = self;
picker.displayedPropertyKeys = #[CNContactGivenNameKey];
[self presentViewController:picker animated:YES completion:nil];
}];
In this case you'll show picker always, without dependance on user's choice. So you should check property availability like that:
if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized)
{
}
My button only registers when it is clicked twice for some reason. Anyone know why?
- (IBAction)refreshButton:(UIButton *)sender {
keynames = [[NSMutableArray alloc] init];
keynums = [[NSMutableArray alloc] init];
Firebase *resp = [[Firebase alloc] initWithUrl: #"https://somelink"];
[resp observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
int x = 0;
[tabView beginUpdates];
for (NSString* key in snapshot.value){
[mutkeynames addObject:key];
[mutkeynums addObject:snapshot.value[key][#"value"]];
x++;
}
[tabView endUpdates];
}];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tabView reloadData];
});
}
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 :)
I'm working on an app that behaves like a photo gallery, and I'm implementing the option to have the user delete photos from their gallery. To accomplish this, I decided to place an invisible button over each picture. When the user hits an "Edit" button, the hidden delete buttons over each picture become active. I'm using the same IBOutlet over each of the hidden buttons for simplicity, and I've tagged each button appropriately in Interface Builder. When the user taps the button over the picture, an alert view appears asking if they really want to delete it. If they click yes, I call removeObjectAtIndex. Here is the code I'm using:
- (IBAction)deleteButtonPressed:(id)sender {
NSLog(#"Sender is %#", sender);
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
int imageIndex = ((UIButton *)sender).tag;
deleteAlertView.tag = imageIndex;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"User Clicked Yes.");
[self.array removeObjectAtIndex: alertView.tag];
}
[self.user setObject:array forKey:#"images"];
}
The issue here is that when I click "Yes" in the alert view, nothing happens. However, if I tap on the image and click "Yes" a second time, the app crashes, and the debug states:
Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray removeObjectAtIndex:]: index (0) beyond bounds (0)' So, I'm not sure where to go from here, I'm still very new to programming and everything looks correct to me. Any help is much appreciated, thanks!
Here is how I add them into the array:
////start of saving////
- (void)viewWillAppear:(BOOL)animated
{
self.user = [NSUserDefaults standardUserDefaults];
self.array = [[self.user objectForKey:#"images"]mutableCopy];
while(self.array == nil)
{
[self.user setObject:[NSMutableArray arrayWithObject:#""] forKey:#"images"];
self.array = [[self.user objectForKey:#"images"]mutableCopy];
NSLog(#"%#",#"attempting to create an array to store the images in");
}
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
NSLog(#"Image on didenterbackground: %#", imageView);
self.array = [NSMutableArray arrayWithObject:[NSData dataWithData:UIImagePNGRepresentation(imageView.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView2.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView3.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView4.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView5.image)]];
[self.user setObject:self.array forKey:#"images"];
[user synchronize];
}
- (void)viewDidLoad
{
self.user = [NSUserDefaults standardUserDefaults];
NSLog(#"It is %#", self.user);
self.array = [[self.user objectForKey:#"images"]mutableCopy];
imageView.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:0]];
imageView2.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:1]];
imageView3.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:2]];
imageView4.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:3]];
imageView5.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:4]];
imageView6.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:5]];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:app];
backToGalleryButton.hidden = YES;
tapToDeleteLabel.hidden = YES;
deleteButton1.hidden = YES;
[super viewDidLoad];
}
- (void)viewDidUnload
{
self.user = nil;
}
////end of saving
///// shows the hidden and invisible "delete" button over each photo.
- (IBAction)editButtonPressed:(id)sender {
grabButton.hidden = YES;
editButton.hidden = YES;
backToGalleryButton.hidden = NO;
tapToDeleteLabel.hidden = NO;
deleteButton1.hidden = NO;
}
- (IBAction)deleteButtonPressed:(id)sender {
NSLog(#"Sender is %#", sender);
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
int imageIndex = ((UIButton *)sender).tag;
deleteAlertView.tag = imageIndex;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"User Clicked Yes.");
NSLog(#"Array: %#, index: %d", self.array, alertView.tag);
[self.array removeObjectAtIndex: alertView.tag];
}
[self.user setObject:array forKey:#"images"];
}
#end
EDIT: This is the code I use to put the objects into the UIImageView from the users camera roll:
- (IBAction)grabImage {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
// Sets the image in the UIImageView
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView3.image == nil) {
imageView3.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView4.image == nil) {
imageView4.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
}
When I added NSLog(#"Array: %#, index: %d", self.array, alertView.tag); just before removeAtIndex the console says 2012-04-03 18:39:39.066 AppName[1631:f803] Array: (null), index: 0. Could that be the cause? I'm not sure why it would be, I think the code looks fine.
Removing the image from the array is not the only step you have to take. Your code is correct for removing the image from the array, which is why you get image out of bounds the second time, but you also need to remove the image from the UI so the user can no longer delete an image that is not there.
There are many oddities with this code but I think the problem is that you are not calling super on your viewwillappear and viewdidload functions. I would get rid of your viewWillAppear method as it serves no purpose.
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!