I am doing a little self learning with Obj-c and interested in making a flash card application. I have an NSArray with objects with 5 images in the array. When the user presses the forward button I am trying to get my UIImageView to show the next image in the array. I get Thread 1: EXC_BAD_ACCESS(Code=2,address=0x0) on the line where I get an image from my array. Here is my current header and implementation file.
#interface WhoAmIViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIImageView *flashcardviewer;
#property (strong, nonatomic) NSArray *aryFlashcards;
#property (nonatomic) NSUInteger *int_counter;
#end
#implementation WhoAmIViewController
#synthesize aryFlashcards;
#synthesize flashcardviewer;
#synthesize int_counter;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
aryFlashcards = [NSArray arrayWithObjects:
[UIImage imageNamed:#"shot_1"],
[UIImage imageNamed:#"shot_2"],
[UIImage imageNamed:#"shot_3"],
[UIImage imageNamed:#"shot_4"],
[UIImage imageNamed:#"shot_5"],
nil];
int_counter = 0;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//back button
- (IBAction)btn_back:(UIButton *)sender {
}
//forward button
- (IBAction)btn_forward:(UIButton *)sender
{
flashcardviewer = [[UIImageView alloc]init];
UIImage *flashcard_next = [UIImage imageNamed:[aryFlashcards objectAtIndex:*(int_counter)]]; //This is where Xcode throws me an error.
flashcardviewer.image = flashcard_next;
int_counter++;
}
//random button
- (IBAction)btn_random:(UIButton *)sender
{
}
You made int_counter a pointer instead of an NSInteger. Try
#property (nonatomic) NSUInteger int_counter;
and
UIImage *flashcard_next = [aryFlashcards objectAtIndex:int_counter];
Try the following code:
//Declare int_counter like this
#property (nonatomic) NSUInteger int_counter;
//Set btn_forward: this way
- (IBAction)btn_forward:(UIButton *)sender
{
//Avoid possible app crash with a if condition
if (int_counter < flashcard_next.count) {
UIImage *flashcard_next = [aryFlashcards objectAtIndex:int_counter];
flashcardviewer.image = flashcard_next;
int_counter++;
} else {
NSLog (#"No more cards");
}
}
You can learn more about NSInteger here.
Your problem is on this line:
UIImage *flashcard_next = [UIImage imageNamed:[aryFlashcards objectAtIndex:*(int_counter)]];
You're creating a UIImage object and passing another UIImage to the method when it's expecting a NSString. Change this to:
UIImage *flashcard_next = [aryFlashcards objectAtIndex:int_counter];
and as mentioned in the other answer, remove the pointer to int_counter.
Your iVar aryFlashcards is already instantiated with 5 images in viewDidLoad method. In your btn_forward method implementation you should replace
UIImage *flashcard_next = [UIImage imageNamed:[aryFlashcards objectAtIndex:*(int_counter)]];
With following provided *(int_counter) is less than aryFlashCards size which looks to be 5 in your example else your app will throw out of bound exception.
UIImage *flashcard_next = [aryFlashcards objectAtIndex:*(int_counter)];
Related
Hi i am very new for ios and in my project i am using PageViewController
for displaying and swiping the images,Ok that's fine
But here i am loading images on my pageViewcontroller from services(i mean url images i am loading)
For this i am using SDWebImage library for loading images,But here i have underlined clearly where i am getting errors below in my RootViewController.m please help me how can i load images in PageViewController using SDWebImage library and what is the wrong in that line please help me
my code:-
PageContentViewController.h
#interface PageContentViewController: UIViewController
#property (weak,nonatomic) IBOutlet UIImageView * ivScreenImage;
#property NSUInteger pageIndex;
#property NSString *imgFile;
#property NSString *txtTitle;
#end
PageContentViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.ivScreenImage.image = [UIImage imageNamed:self.imgFile];
}
RootViewController.h
#import <SDWebImage/UIImageView+WebCache.h>
#interface RootViewController : UIViewController
<UIPageViewControllerDataSource>
#property (nonatomic,strong) UIPageViewController *PageViewController;
#property (nonatomic,strong) NSArray *arrPageImages;
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index;
#end
RootViewController.m
- (void)viewDidLoad{
[super viewDidLoad];
arrPageImages =#[#"http://www.domain.com/path/to/image1.jpg",#"http://www.domain.com/path/to/image2.jpg",#"http://www.domain.com/path/to/image3.jpg"];
}
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index{
if (([self.arrPageTitles count] == 0) || (index >= [self.arrPageTitles count])) {
return nil;
}
// Create a new view controller and pass suitable data.
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
pageContentViewController.imgFile setImageWithURL:[[[NSURL URLWithString:[self.arrPageImages[index]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
--------------------------------------------------------------------------------
pageContentViewController.pageIndex = index;
return pageContentViewController;
}
SDWebImage method for setting image for UIImageView is
sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder
also imgFile variable should be UIImageView.
Before beginning, I thought I should let you all know that I'm a self-taught beginner with no formal background what so ever.
My Goal: To display parsed HTML data from www.3v3live.com into various views in my app.
General Plan for implementation: I will create a reusable method that I can call to parse different pages of the site. It will have three parameters, including: a url, an Xpath query, and a type of data (input as a string and converted into a class by the method). The method shall return the gathered data in the type of data (from third parameter) in an array.
My Errors: 1) "No known class method for selector 'parseData:::'
2) "No known class method for selector 'stringFromArray:'
My OutPut: none
My Attempts to fix the errors: 1) I've added them to the .h file and interface of .m
2) I've added in a protocol (recommended by an answer on here)
3) I've converted the methods to instance methods (and back)
4) I've cleaned and run the project
Note: The error is at the line in the "textSet" method towards the bottom, and the "makeSlideShow" and "getText" methods are the precursors to my new method that is erroring (the precursors errored too).
My Code (ignore comments):
(ViewController.h
#import <UIKit/UIKit.h>
#protocol dataParsingVC <NSObject>
+ (id) stringFromArray: (NSArray*) arr;
+ (id) parseData: (NSString*) urlS : (NSString*) path : (NSString*) typeOfDataToReturn;
#end
#interface ViewController : UIViewController <NSURLConnectionDataDelegate>
// Drop Down Menu Buttons
#property (weak, nonatomic) IBOutlet UIButton *scheduleButton;
#property (weak, nonatomic) IBOutlet UIButton *newsButton;
#property (weak, nonatomic) IBOutlet UIButton *photosButton;
#property (weak, nonatomic) IBOutlet UIButton *docsButton;
#property (weak, nonatomic) IBOutlet UIButton *stagesButton;
#property (weak, nonatomic) IBOutlet UIButton *faqsButton;
#property (weak, nonatomic) IBOutlet UIButton *resultsButton;
#property (weak, nonatomic) IBOutlet UIButton *contactButton;
#property (weak, nonatomic) IBOutlet UIButton *finderButton;
- (IBAction)menuButton:(UIBarButtonItem *)sender;// Menu Button Open & Close
// WV = Web View; use as few as possible
#property (weak, nonatomic) IBOutlet UIWebView *hostATournamentWV; // for the poll
// SV = scroll view
#property (weak, nonatomic) IBOutlet UIScrollView *menuSV;
#property (weak, nonatomic) IBOutlet UIScrollView *homeSideTabsSV;
// Slide Show Image View
#property (weak, nonatomic) IBOutlet UIImageView *ssIV;
// TV = text view
#property (weak, nonatomic) IBOutlet UITextView *skillLevelsTV;
#property (weak, nonatomic) IBOutlet UITextView *homeTV;
#property (weak, nonatomic) IBOutlet UITextView * rulesTV;
// CV = container view
#property (weak, nonatomic) IBOutlet UIView *sideTabsCV;
// Arrays
#property (weak,nonatomic) NSMutableArray * _ssImagesArray;
#property (weak,nonatomic) NSMutableArray * _textArray;
// Error handling
#property (strong, nonatomic) NSMutableData * _responseData; // got warning in .m when prop was weak
// parsing related methods
+ (id) parseData: (NSString*) urlS : (NSString*) path : (NSString*) typeOfDataToReturn;
+ (id) stringFromArray: (NSArray*) arr;
#end
ViewController.m
#import "ViewController.h"
#import "TFHpple.h"
#import "TFHppleElement.h"
#interface ViewController ()
+ (id) parseData:(NSString *)urlS :(NSString *)path :(NSString *)typeOfDataToReturn;
+ (id) stringFromArray:(NSArray *)arr;
#end
#implementation ViewController
#synthesize _responseData;
#synthesize menuSV;
#synthesize homeSideTabsSV;
#synthesize homeTV;
#synthesize ssIV;
#synthesize hostATournamentWV;
#synthesize rulesTV;
#synthesize skillLevelsTV;
#synthesize _ssImagesArray;
#synthesize _textArray;
#synthesize scheduleButton;
#synthesize newsButton;
#synthesize photosButton;
#synthesize docsButton;
#synthesize stagesButton;
#synthesize faqsButton;
#synthesize resultsButton;
#synthesize contactButton;
#synthesize finderButton;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction) menuButton:(UIBarButtonItem *)sender {// When Drop Down Menu is pressed
//self.menuSV.contentSize = CGSizeMake(160, 160); // Make it so Scroll View (contains buttons) can scroll
if (self.homeSideTabsSV.hidden) // if buttons aren't showing, then uncover them
{
self.homeSideTabsSV.hidden = false;
} else if (self.homeSideTabsSV.hidden == false) // else (they're showing) hide them
{
self.homeSideTabsSV.hidden = true;
}
}
+ (id) stringFromArray : (NSArray *) arr // creates a string when given an array
{
NSString * result = [arr description];
return result;
}
+ (id) parseData: (NSString*) urlS : (NSString*) path : (NSString*) typeOfDataToReturn
{
// Set up request
NSURL * url = [NSURL URLWithString:urlS];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
NSURLResponse * response = nil;
NSError * error = nil;
// Send request
NSData * gatheredData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error) {return error;}
// set up parser
TFHpple * Parser = [TFHpple hppleWithHTMLData:gatheredData];
// Parse data
NSArray * Nodes = [Parser searchWithXPathQuery:path];
// Set up array to be returned
NSMutableArray * array = [[NSMutableArray alloc]initWithCapacity:0];
// Insert parsed data into "array"
for (TFHppleElement * element in Nodes)
{
// tell returned data it's class
id dataType = NSClassFromString(typeOfDataToReturn);
id returnedData = [[dataType alloc] init];
// set returnedData's value and insert it into "array"
returnedData= [[element firstChild] content];
[array addObject:returnedData];
}
return array;
}
- (void) textSet // setText already exists, so this one is textSet
{
// set homeTV's text = the string form (from "stringFromArray") of the array from "parseData"
[self.homeTV setText:[NSString stringFromArray:[ NSArray parseData: #"http://www.3v3live.com" : #"//p" : #"NSString"]]];
}
// call method with url & path to get text
- (id) getText:(NSURL*) url :(NSString*) path
{
NSData * gatheredText = [NSData dataWithContentsOfURL:url];
TFHpple * textParser = [TFHpple hppleWithHTMLData: gatheredText];
NSArray * textNodes = [textParser searchWithXPathQuery:path];
NSMutableArray * textArray = [[NSMutableArray alloc]initWithCapacity:0];
for (TFHppleElement * element in textNodes)
{
NSString * text = [[element firstChild] content]; // set text's value
[textArray addObject:text]; // add text to textArray
}
int z = [_textArray count]; // set z = end of _textArray
NSRange range = NSMakeRange(z, [textArray count]); // make a range from z to end of textArray
NSIndexSet * indexSet = [NSIndexSet indexSetWithIndexesInRange:range]; // make an indexSet from range
[_textArray insertObjects:textArray atIndexes:indexSet]; // insert new parsed info at end of _textArray
return textArray;
}
- (void) makeSlideShow { // gets images for Slide Show
NSURLRequest * imagesURL = [NSURLRequest requestWithURL:[NSURL URLWithString: #"http://www.3v3live.com"]]; // request connection
NSURLResponse * response = nil;
NSError * error = nil;
NSData * gatheredImages = [NSURLConnection sendSynchronousRequest:imagesURL returningResponse:&response error:&error];// get raw data
if (error == nil)
{
// Parse data here
TFHpple *imageParser1 = [TFHpple hppleWithHTMLData:gatheredImages]; // parses for almost all images in slide show
TFHpple *imageParser2 = [TFHpple hppleWithHTMLData:gatheredImages]; // parses for displayed image
NSString * parsePath1 = #"//div[#class ='newsSlideShow-article']"; // not shown pics path
NSString * parsePath2 = #"//div[#class = 'newsSlideShow-article current']"; // shown pic path
NSArray * Nodes = [imageParser1 searchWithXPathQuery:parsePath1]; // not shown pics array
NSArray * currentArticleArray = [imageParser2 searchWithXPathQuery:parsePath2]; // stores shown image
UIImage * currentArticle = [currentArticleArray objectAtIndex:0]; // displayed image in slide show should be first in the above array
[_ssImagesArray addObject:currentArticle ]; // add in displayed pic
int x = 1;
for (TFHppleElement * element in Nodes)// seperate collected data into pics; inserts rest of pics into imagesArray
{
x++;
UIImage * image = [UIImage imageWithData:[NSURL URLWithString:[element objectForKey:#"href"]]]; // set image's value
[_ssImagesArray addObject:image]; // add it to imagesArray
}
}
};
int j = 1; // counter for loopSlideShow
- (void) loopSlideShow // runs the slide show with gathered images from createSlideShow
{
int delayTime = 5; // how long each pic is shown
while (self.ssIV) // while the slideShowPic exists
{
if (j == [_ssImagesArray count]) // if it's reached the last pic, loop back to beggining of Slide Show
{
j = 1;
} else // else go on to next pic
{
j++;
};
[ssIV setImage:[_ssImagesArray objectAtIndex:j]]; // tell slide show which pic to display
[self performSelector:#selector(loopSlideShow) withObject:self afterDelay:delayTime]; // show each picture for X seconds
}
};
#end
It looks like -[ViewController parseData:::] is actually a method on ViewController so it will not make sense if you call it on NSArray
If you keep it as a class method then you should call it with
[self.class parseData: #"http://www.3v3live.com" : #"//p" : #"NSString"]
or change it to an instance method and call it with
[self parseData: #"http://www.3v3live.com" : #"//p" : #"NSString"]
Either way this is a really poorly named method and it seems like some fundamental object oriented programming concepts are missing. Apple have some really good resources on getting started with Objective-C and iOS development.
Trying to use ZBar to capture a barcode. I have the following code in place at the moment. The scanner shows, and appears to scan the barcode as the green overlay appears around the code. I don't know how to capture the decoded results.
I'm probably going about it wrong, so thought I'd ask. Nothing is output to the console when scanning, so don't think the didReadSymbols is being called at all.
.h
#interface ScannerViewController : UIViewController <ZBarReaderDelegate> {
}
#property (strong, nonatomic) IBOutlet UILabel *readerResult;
#property (strong, nonatomic) IBOutlet UIView *readerView;
#property (strong, nonatomic) IBOutlet ZBarReaderView *zbr;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
// force class to load so it may be referenced directly from nib
[ZBarReaderViewController class];
ZBarReaderViewController *reader= [ZBarReaderViewController new];
reader.readerDelegate = self;
ZBarImageScanner *scanner = reader.scanner;
//reader.cameraOverlayView = self.readerView;
[scanner setSymbology: 0
config: ZBAR_CFG_ENABLE
to: 1];
[reader setShowsZBarControls:NO];
[reader.readerView start];
self.zbr = reader.readerView;
[self.view addSubview:reader.view];
}
- (void) zbr: (ZBarReaderView*) view
didReadSymbols: (ZBarSymbolSet*) syms
fromImage: (UIImage*) img
{
NSLog(#"Scanner used");
//do something useful with results and display resultText in resultViewController
for(ZBarSymbol *sym in syms) {
NSLog(#"Logged");
//return resultText;
break;
}
}
Any advice would be great. I'm getting very confused with this at the moment. Cheers.
When I look at the documentation for ZBar, I see the delegate method signature is:
- (void) readerView:(ZBarReaderView*)readerView didReadSymbols:(ZBarSymbolSet*)symbols fromImage:(UIImage*)image
which is not the same thing as what you have above. Replace your "zbr" with "readerView" and your delegate method should get called.
I added the below to the ScannerViewController interface.
ZBarReaderViewController *reader;
I then changed the readerView method for the below, and it works perfectly.
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
id<NSFastEnumeration> results =
[info objectForKey: ZBarReaderControllerResults];
UIImage *image =
[info objectForKey: UIImagePickerControllerOriginalImage];
NSString *resultText = [[NSString alloc] init];
for(ZBarSymbol *sym in results) {
NSLog(#"%#", sym.data);
resultText = sym.data;
//return resultText;
break;
}
}
I have a barcode scanner on one view, and after the user has scanned the barcode, the app takes them to another view (BoilerDetails) where the barcode text field has been pre-filled.
I understand that the viewcontroller is null when it hasn't come into view and I can'tchange the UITextField text directly. This so far has given me an error.. How can I fix this?
BarcodeScannerViewController.m
BoilerDetailsViewController *viewCtrl = [[BoilerDetailsViewController alloc] initWithNibName:nil bundle:nil];
[viewCtrl setBarcode:strBarcode];
[self.navigationController pushViewController:viewCtrl animated:YES];
BoilerDetailsViewController.h
#interface BoilerDetailsViewController : SubViewControllerBase
#property (retain, nonatomic) NSString *barcode;
#property (retain, nonatomic) IBOutlet UITextField *barcodeField;
- (void)setBarcode:(NSString*)strBarcode;
#end
BoilerDetailsViewController.m
-(void)setBarcode:(NSString *)strBarcode
{
self.barcode = strBarcode;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[_barcodeField setText:self.barcode];
// Do any additional setup after loading the view from its nib.
}
-(void)setBarcode:(NSString *)strBarcode
{
self.barcode = strBarcode;
}
I think that these strings give you infinite loop. According to your logic you should use:
-(void)setBarcode:(NSString *)strBarcode
{
self.barcodeField.text = strBarcode;
}
or
#syntesize barcode = _barcode;
-(void)setBarcode:(NSString *)strBarcode
{
[_barcode autorelease];
_barcode = [strBarcode retain] //in case of no ARC
}
Depends on what you want (store a string or set a label).
you just have to synthesize the barcode and in ViewDidload just write this code [_barcodeField setText:barcode]; and good to Go.
First of all, this is wrong
-(void)setBarcode:(NSString *)strBarcode
{
self.barcode = strBarcode;
}
self.barcode = strBarcode; itself calls the setter.
depending on your ios version you shud write:
//for ARC environment
-(void)setBarcode:(NSString *)strBarcode
{
_barcode = strBarcode;
}
//since default association in ARC is strong
before this do #synthesize barcode = _barcode;
//and for non-ARC environment, since your property is retain type
-(void)setBarcode:(NSString *)strBarcode
{
if (_barcode != barcode) {
[_barcode release];
_barcode = [barcode retain];
}
}
And you will be OK.
.h
IBOutlet UIImageView *photoImageView;
UIImage *photo;
.m (in viewWillAppear)
photoImageView.image = photo;
After view appeared, I can't change photoImageView by using:
photoImageView.image = [UIImage imageNamed:#"XXX.png"];
but changing the value of photo works.
photo = [UIImage imageNamed:#"XXX.png"];
How does it work?
Try this code.
//YourController.h
#interface YourController : UIViewController
{
UIImageView* _photoImageView;
}
#property (retain, nonatomic) IBOutlet UIImageView *photoImageView;
- (IBAction)changeImageAction:(id)sender;
#end
//YourController.m
#synthesize photoImageView = _photoImageView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.photoImageView.image = [UIImage imageNamed:#"img.png"];
}
- (IBAction)changeImageAction:(id)sender {
self.photoImageView.image = [UIImage imageNamed:#"img_2.png"];
}
Some notes.
First of all, you have to link your photoImageView IBOutlet correctly in XCode. For test purposes I created a test button (UIButton) that is linked to an IBAction. The UIImageView and the test button (I created both with IB) are childs of YourController view.
Remember to import your images into your project and to release memory in dealloc and in viewDidUnload.
- (dealloc)
{
[_photoImageView release];
_photoImageView = nil;
[super dealloc]
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.photoImageView = nil;
}
Hope it helps.
Edit
The code is not ARC oriented but with few modifications it is possible to run it also with ARC.