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;
}
}
Related
I am trying to get the gps information from the RTK in DJI M600 Pro by using an ios app, I have looked at DJI Mobile SDK API reference, and I have found some RTK API . When the drone is starting up, the property "isRTKBeingUsed" should be "YES" ,but I can't get the result.
Any help would be greatly appreciated! Here is my code:
#import "ViewController.h"
#import <DJISDK/DJISDK.h>
#import "DJIAppActivationManager_InternalTesting.h"
#import<DJISDK/DJIRTK.h>
#define WeakRef(__obj) __weak typeof(self) __obj = self
#define WeakReturn(__obj) if(__obj ==nil)return;
void ShowResult(NSString *format, ...)
{...
}
#interface ViewController ()<DJIAppActivationManagerDelegate, DJISDKManagerDelegate,DJIRTKDelegate>
...
...
#property (weak, nonatomic) IBOutlet UILabel *isusing;
#property(strong, nonatomic) DJIRTK * rtk1;
#property(strong, nonatomic) DJIRTKState * rtkstate1;
#end
#implementation ViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self registerApp];
[self updateUI];
self.rtk1 = [[DJIRTK alloc] init];
self.rtkstate1 = [[DJIRTKState alloc] init];
[self rtk:_rtk1 didUpdateState:_rtkstate1];
}
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void) rtk:(DJIRTK *)rtk didUpdateState:(DJIRTKState *)state
{
self.shifoushiyong.text = [NSString stringWithFormat:#"%d",state.isRTKBeingUsed];
}
- (void)registerApp
{
[DJISDKManager registerAppWithDelegate:self];
}
-(void)updateUI
{
...
}
...
#end
TLDR: You are using the RTK delegate method the wrong way.
didUpdateState: is a delegate method. You need to pass a delegate object to your RTK object. When data comes from the aircraft, didUpdateState will be called. You don't have to do it manually.
Furthermore, you shouldn't init your own RTK object:
1/ Once you have confirmation the SDK has registered (delegate method of DJISDKManager), get the product
- (void)appRegisteredWithError:(NSError *_Nullable)error {
DJISDKManager.product
// continue here
}
https://developer.dji.com/api-reference/ios-api/Components/SDKManager/DJISDKManager.html#djisdkmanager_product_inline
2/ Verify it's a DJIAircraft class
if ([[DJISDKManager.product class] isKindOf:[DJIAircraft class]) {
// Continue here
}
https://developer.dji.com/api-reference/ios-api/Products/Aircraft/DJIAircraft.html?search=djiaircraft&i=0&
3/ Get the RTK object from there:
DJIRTK *rtk = aircraft.flightController.RTK;
https://developer.dji.com/api-reference/ios-api/Components/FlightController/DJIFlightController.html#djiflightcontroller
4/ Set the delegate to RTK (a class that implemented DJIRTKDelegate - assuming self here)
rtk.delegate = self;
https://developer.dji.com/api-reference/ios-api/Components/RTK/DJIRTK.html#djirtk_protocol_inline
5/ Get the data in the delegate method like you did.
- (void)rtk:(DJIRTK *_Nonnull)rtk didUpdateState:(DJIRTKState *_Nonnull)state {
// Show me the data
}
https://developer.dji.com/api-reference/ios-api/Components/RTK/DJIRTK.html#djirtk_updatertkstate_inline
I am trying to print out a list of objects in my NSMutableArray via NSLog, but for some reason, it is appearing to be null. Basically, I have a to-do list that when the user enters a new string to add to the tableview, it will also add that item to the NSArray so I can save it to the device.
AddToDoItemViewController.m
#import "AddToDoItemViewController.h"
#import "ToDoItem.h"
#interface AddToDoItemViewController ()
#property (weak, nonatomic) IBOutlet UITextField *textField;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton;
#end
#implementation AddToDoItemViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.toDoItem.itemList = [[NSMutableArray alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if (sender != self.saveButton) return;
if (self.textField.text.length > 0) {
self.toDoItem = [[ToDoItem alloc] init];
self.toDoItem.itemName = self.textField.text;
self.toDoItem.completed = NO;
NSLog(#"Trying to add to array: %#", self.toDoItem.itemName);
[self.toDoItem.itemList addObject:self.toDoItem.itemName];
NSLog(#"Array contents: %#", self.toDoItem.itemList);
}
}
#end
AddToDoItemViewController.h
#import <UIKit/UIKit.h>
#import "ToDoItem.h"
#interface AddToDoItemViewController : UIViewController
#property ToDoItem *toDoItem;
#end
ToDoItem.h
#import <Foundation/Foundation.h>
#interface ToDoItem : NSObject
#property NSString *itemName;
#property BOOL completed;
#property (readonly) NSDate *creationDate;
#property NSMutableArray *itemList;
#end
Now from my AddToDoItem.m file, when I use NSLog to try to output the Array I get this:
2016-02-24 01:04:49.668 ToDoList[4025:249117] Trying to add to array: ok
2016-02-24 01:04:49.669 ToDoList[4025:249117] Array contents: (null)
**** The 'ok' was the text I entered *****
You did not initialise the array before adding to it, add self.toDoItem.itemList = [NSMutableArray new];
Edit:
oh i see you added self.toDoItem.itemList = [[NSMutableArray alloc] init]; in the viewDidLoad, but this is not the right place to put it, it should be after self.toDoItem = [[ToDoItem alloc] init]; or inside the init method of ToDoItem
First, you need create an init method at ToDoItem.m
- (id)init {
self = [super init];
if (self) {
// Any custom setup work goes here
self.itemList = [[NSMutableArray alloc] init];
}
return self;
}
then run your project again.
You are initialising the Array( itemList ) before ToDoItem is initialised, so initialised array remains nil. So, it cannot store any object.
Modify code as below,
self.toDoItem = [[ToDoItem alloc] init];
self.toDoItem.itemList = [[NSMutableArray alloc] init];
you can add above lines of code either at viewDidLoad or at Segue Method
hope it helps you.
STILL NO SOLUTION - REDUCED TEST CASE PROJECT HERE:
http://www.friendlycode.co.uk/assets/Bugfix.zip
I'm new to Xcode/Objective C and have done a lot of research but cannot find an answer. There are loads of similar questions here but none of them have helped me solve this.
Files:
app.h
app.m
Settings.h
Settings.m
I have some background music playing which starts when the app is launched via ViewDidLoad in the ViewController.m file.
I am trying to stop this from the Settings.m file if the Music switch is touched and set to off.
Please see code below (have removed unnecessary outlets/methods etc)
The NSLog outputs 'attempting to stop audio' but audio is not stopped. I think I have referenced the ViewController class correctly so unsure why it won't stop?
app.h
#import <UIKit/UIKit.h>
#import <Social/Social.h>
#import "AVFoundation/AVAudioPlayer.h"
#interface ViewController : GAITrackedViewController <AVAudioPlayerDelegate, UIActionSheetDelegate>
{
// removed
}
#property (nonatomic, retain) AVAudioPlayer *BackgroundMusicPlayer;
#end
app.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Play Background music
[self PlayBackgroundMusic];
}
-(void)PlayBackgroundMusic
{
NSString* resourcePath = [[NSBundle mainBundle]
pathForResource:#"music-file"
ofType:#"aiff"];
NSLog(#"Path to play: %#", resourcePath);
NSError* err;
//Initialize our player pointing to the path to our resource
_BackgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath] error:&err];
if( err ){
//bail!
NSLog(#"Failed with reason: %#", [err localizedDescription]);
}
else{
//set our delegate and begin playback
_BackgroundMusicPlayer.delegate = self;
[_BackgroundMusicPlayer play];
_BackgroundMusicPlayer.numberOfLoops = -1;
_BackgroundMusicPlayer.currentTime = 0;
_BackgroundMusicPlayer.volume = 0.5;
}
}
Settings.h
#import <UIKit/UIKit.h>
#import "app.h"
#interface Settings : GAITrackedViewController <AVAudioPlayerDelegate, UIActionSheetDelegate>
{
IBOutlet UIButton *BackButton;
IBOutlet UISwitch *MusicSwitch;
IBOutlet UISwitch *SoundFXSwitch;
// Get instance of ViewController object
ViewController *home;
}
-(IBAction)BackButton:(id)sender;
-(IBAction)ToggleMusic:(id)sender;
-(IBAction)ToggleSoundFX:(id)sender;
#end
Settings.m
#import "Settings.h"
#interface Settings ()
#end
#implementation Settings
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)ToggleMusic:(id)sender {
// Get instance of ViewController object
//home = [[ViewController alloc] init];
if (MusicSwitch.on)
{
[home.BackgroundMusicPlayer play];
}
else {
[home.BackgroundMusicPlayer stop];
NSLog(#"Attempting to stop audio");
}
}
-(IBAction)ToggleSoundFX:(id)sender {
if (SoundFXSwitch.on)
{
}
else{
}
}
-(IBAction)BackButton:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
I think the problem is with the ViewController *home.
Your AvAudioPlayer object is in the app.h in the interface ViewController.
But in your code , you are not initialising the ViewController object "home"
in settings.m. So effectively , you are trying to access and stop a player that
is not created.
To access the AVAudioPlayer object add the following code in your viewDidload of settings.h.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//initialise the audioPlayer object.
home=[[ViewController alloc] init];
}
In your Settings.h , declare the ViewController property as assign
#interface Settings : GAITrackedViewController <UIActionSheetDelegate>
{
#property (nonatomic, assign) ViewController *home;
}
-(IBAction)ToggleMusic:(id)sender {
if (MusicSwitch.on)
{
[self.home.BackgroundMusicPlayer play];
}
else {
[self.home.BackgroundMusicPlayer stop];
}
}
From your app.m , assign the home property as self _BackgroundMusicPlayer.home = self;
-(void)PlayBackgroundMusic
{
NSString* resourcePath = [[NSBundle mainBundle]
pathForResource:#"music-file"
ofType:#"aiff"];
NSLog(#"Path to play: %#", resourcePath);
NSError* err;
//Initialize our player pointing to the path to our resource
_BackgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath] error:&err];
if( err ){
//bail!
NSLog(#"Failed with reason: %#", [err localizedDescription]);
}
else{
//set our delegate and begin playback
_BackgroundMusicPlayer.delegate = self;
settingsViewObj.home = self; //recommended after the 'Settings' view allocation code.
[_BackgroundMusicPlayer play];
_BackgroundMusicPlayer.numberOfLoops = -1;
_BackgroundMusicPlayer.currentTime = 0;
_BackgroundMusicPlayer.volume = 0.5;
}
}
Notes:
Read more about object communication
Read more about Objective C coding standards
Read more about class hierarchy
If I am understanding your code correctly, it seems you are creating a instance of your initial view controller and trying to stop the music player property of that instance. If that is the case, the music player you are trying to stop is already stopped, because it is a a separate instance of AVAudioPlayer that was created when you created an instance of your ViewController. In order to stop the music player from the first view controller, you could try this:
In the Settings.h file, add an AVAudioPlayer property just like in app.h
#property (strong, nonatomic) AVAudioPlayer *backgroundMusic;
Then when segueing to the settings view controller, pass the audio player to the new controller using prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"YourSegueName"]) {
if([segue.destinationViewController isKindOfClass:[YourSettingsClass class]]) {
YourSettingsClass *destination = segue.destinationViewController;
destination.backgroundMusic = self.BackgroundMusicPlayer;
}
}
}
You should now be able to simply call [self.backgroundMusic stop] and stop your tunes.
Ensure that you #import your Settings controller class in your app class to access it in the prepareForSegue method.
You can't access the instance of an object of another class created by it, by importing
it.Here You have to access the same object instance , in order to stop the AVAudioPlayer.
So you have to place the object somewhere unique, like AppDelegate.
Try declaring the AVAudioPlayer in the appdelegate.h.
In Appdeleagte.h
#property (nonatomic, strong) AVAudioPlayer *BackgroundMusicPlayer;
and in your app.h you can access the player as follows.
AppDelegate *appDelegate;
//in your viewDidLoad
appDelegate=[[UIApplication sharedApplication]delegate];
//in your PlayBackGroundMusic
appdelegate.avAudioPlayer=[[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath] error:&err];
[appDelegate.avAudioplayer play];
in your settings.h
AppDeleagte *appDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//initialise the audioPlayer object.
appDelegate=[[UIApplication sharedApplication]delegate];
}
you can stop the player by
[appDelegate.avAudioPlayer stop];
You can download the fixed project here
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)];
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.