I have a watch app that is being updated for watch os 2. The sendmessage does not wake the parent app. According to the transition documentation is this how you would wake a parent in the background.
"The iOS app is always considered reachable, and calling this method from your Watch app wakes up the iOS app in the background as needed."
Has anyone had this problem? The only way to get data is to have the parent app already open.
Another weird thing is the watch app changes the uitableview for the parent app. When the -(IBAction)yesterdaySales:(id)sender is called on the watch, it changes the parent app UITableView instead of the watch tableview.
InterfaceController.m
#import "InterfaceController.h"
#import "MyRowController.h"
#import "ftDateParser.h"
#import WatchKit;
#import <WatchConnectivity/WatchConnectivity.h>
#interface InterfaceController() <WCSessionDelegate>
{
IBOutlet WKInterfaceDevice *it;
BOOL tday;
IBOutlet WKInterfaceLabel *lblCompany;
}
#end
#implementation InterfaceController
#synthesize myTable = _myTable;
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
if([WCSession isSupported]){
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
//[self requestInfoPhone];
[self getToday];
}
- (void)willActivate {
// This method is called when watch view controller is about to be visible to user
[super willActivate];
}
- (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
}
-(void)requestInfoPhone{
NSDictionary *dic = #{#"request":#"ySales"};
[[WCSession defaultSession] sendMessage:dic
replyHandler:^(NSDictionary *replyInfo){
NSLog(#"The Reply: %#", replyInfo);
NSDictionary *location = replyInfo;
NSString *name = location[#"label"];
NSString *totalSales = location[#"totalSales"];
// NSString *test2 = location[#"rowText"];
NSMutableArray *sales = [[NSMutableArray alloc]init];
NSMutableArray *storeNames = [[NSMutableArray alloc]init];
sales = location[#"rowText"];
storeNames = location[#"storeNames"];
[self loadTable:sales names:storeNames company:name];
[_labelName setText:name];
[_labelTotalSales setText:totalSales];
tday = YES;
}
errorHandler:^(NSError *error){
NSLog(#"%#", error);
}
];
}
-(void)loadTable:(NSMutableArray*)tester names:(NSMutableArray*)names company:(NSString *)company{
[_myTable setNumberOfRows:[tester count] withRowType:#"row"];
[_labelName setText:company];
for (int i = 0; i < [tester count]; i++) {
MyRowController *vc = [_myTable rowControllerAtIndex:i];
[vc.testLabel setText:[ftDateParser currencyFormat: tester[i]]];
[vc.nameLabel setText:[ftDateParser parseName:names[i]]];
}
[_myTable scrollToRowAtIndex:(0)];
}
-(IBAction)yesterdaySales:(id)sender{
if (tday) {
[_ydaySales setTitle:#"Today Sales"];
[self requestInfoPhone];
}
else{
[_ydaySales setTitle:#"Yesterday Sales"];
[self getToday];
}
}
-(void)getToday{
NSDictionary *dic = #{#"request":#"todaySales"};
[[WCSession defaultSession] sendMessage:dic
replyHandler:^(NSDictionary *replyInfo){
NSDictionary *location = replyInfo;
NSString *name = location[#"label"];
NSString *totalSales = location[#"totalSales"];
// NSString *test2 = location[#"rowText"];
NSMutableArray *sales = [[NSMutableArray alloc]init];
NSMutableArray *storeNames = [[NSMutableArray alloc]init];
sales = location[#"rowText"];
storeNames = location[#"storeNames"];
[self loadTable:sales names:storeNames company:name];
[_labelName setText:name];
[_labelTotalSales setText:totalSales];
tday = YES;
}
errorHandler:^(NSError *error){
NSLog(#"%#", error);
}
];
}
#end
Parent.m
-(void)setUpAppForWatch{
done = NO;
if([WCSession isSupported]){
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
}
-(void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *,id> *)message replyHandler:(void (^)(NSDictionary<NSString *,id> * _Nonnull))replyHandler{
/*UIApplication *application = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier identifier = UIBackgroundTaskInvalid;
dispatch_block_t endBlock = ^ {
if (identifier != UIBackgroundTaskInvalid) {
[application endBackgroundTask:identifier];
}
identifier = UIBackgroundTaskInvalid;
};
identifier = [application beginBackgroundTaskWithExpirationHandler:endBlock];*/
[self setUpAppForWatch];
[self getTheDate];
startDate = todayDay;
endDate = tomorrow;
//[self getTodaySalesforWatch];
NSString *currency = [ftDateParser currencyFormat:totalSales];
NSDictionary *dic = #{#"label": [NSString stringWithFormat:#"%#", #"Town Crier, Inc."],
#"totalSales": currency,
#"rowText": storeSalesData,//[NSString stringWithFormat:#"%#", currency]
#"storeNames":storeNames
};
NSString *request = [message objectForKey:#"request"];
if ([request isEqualToString:#"todaySales"]) {
[self getTodaySalesforWatch];
}
else if ([request isEqualToString:#"ySales"]){
[self connectToWebService];
}
if (done) {
replyHandler(dic);
}
}
Edit:
Maybe the changes to the parent app were happening before, but I didn't know cause the app was running in the background. Still can't get it to wake the parent app.
You don't link to the source of the quote at the top of your question but it must be referring to the openParentApplication method of WatchKit 1. Devices running WatchOS 2.0 cannot call openParentApplication.
The method you're implementing in the code in your question is for a WCSession, which only works for immediate communication between a WatchKit app extension and an iOS app that are both running at the same time. This method does not cause your iOS app to launch, neither in the background nor in the foreground. Other asynchronous communication methods must be used if both apps are not running at the time.
Related
I am trying use CoreData, but when I add it to my project I only get two new methods :
- (NSPersistentContainer *)persistentContainer
and
- (void)saveContext
Now I can't get old methods to work with CoreData, and I can't find any tutorials with these new methods and Objective-C. How can I save and get data from CoreData using persistentContainer in Xcode 8 with Objective-c?
You can Get context as -
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
or as in Objective-C
NSManagedObjectContext *context = ((AppDelegate*)[[UIApplication sharedApplication] delegate]).persistentContainer.viewContext;
And fetch data like -
var resultArray = try self.context.fetch(EntityName.fetchRequest())
or as in Objective-C
NSFetchRequest<EntityName *> *fetchRequest = [EntityName fetchRequest];
NSError *error ;
NSArray *resultArray= [context executeFetchRequest:fetchRequest error:&error];
And fetch data with sorting -
var resultArray = [EntityName]()
do {
let request : NSFetchRequest<EntityName> = EntityName.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "somekey", ascending: true)
let sortDescriptors = [sortDescriptor]
request.sortDescriptors = sortDescriptors
resultArray = try self.context.fetch(request)
} catch {
print("Error")
}
or as in Objective-C
NSFetchRequest<EntityName *> *fetchRequest = [EntityName fetchRequest];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"someKey" ascending:YES];
fetchRequest.sortDescriptors = #[sortDescriptor];
NSError *error ;
NSArray *resultArray= [context executeFetchRequest:fetchRequest error:&error];
And add data like -
let entityNameObj = EntityName(context: context)
entityNameObj.title = "title"
or as in Objective-C
NSManagedObject *entityNameObj = [NSEntityDescription insertNewObjectForEntityForName:#"EntityName" inManagedObjectContext:context];
[entityNameObj setValue:#"someValue" forKey:#"someKey"];
And save context like -
do {
try self.context.save()
} catch _ as NSError {
print("Error")
}
or as in Objective-C
[((AppDelegate*)[[UIApplication sharedApplication] delegate]) saveContext];
-(void)profileDatabase {
NSManagedObjectContext* context=[ADM.persistentContainer viewContext];
NSManagedObject *profile=[NSEntityDescription insertNewObjectForEntityForName:#"Profile" inManagedObjectContext:context];
[profile setValue:[self.serverResponseOfProfileDict objectForKey:#"firstName"] forKey:#"firstName"];
[profile setValue:[self.serverResponseOfProfileDict objectForKey:#"surName"] forKey:#"surName"];
[profile setValue:[self.serverResponseOfProfileDict objectForKey:#"batchID"] forKey:#"batchID"];
[profile setValue:[self.serverResponseOfProfileDict objectForKey:#"profileImagePath"] forKey:#"profileImagePath"];
[profile setValue:[self.serverResponseOfProfileDict objectForKey:#"registeredEmail"] forKey:#"registeredEmail"];
[profile setValue:[self.serverResponseOfProfileDict objectForKey:#"role"] forKey:#"role"];
[profile setValue:[self.serverResponseOfProfileDict objectForKey:#"studentID"] forKey:#"studentID"];
NSLog(#"userObj:%#",profile);
NSError* error;
[context save:&error];
NSFetchRequest *fetchRequest=[[NSFetchRequest alloc]initWithEntityName:#"Profile"];
fetchRequest.returnsObjectsAsFaults=NO;
NSArray* results=[context executeFetchRequest:fetchRequest error:&error];
NSLog(#"Result:%#",results);
NSManagedObject *result=[results objectAtIndex:0];
[ADM.databaseResponseOfProfileDict setObject:[result valueForKey:#"firstName"] forKey:#"firstName"];
[ADM.databaseResponseOfProfileDict setObject:[result valueForKey:#"surName"] forKey:#"surName"];
[ADM.databaseResponseOfProfileDict setObject:[result valueForKey:#"batchID"] forKey:#"batchID"];
[ADM.databaseResponseOfProfileDict setObject:[result valueForKey:#"profileImagePath"] forKey:#"profileImagePath"];
[ADM.databaseResponseOfProfileDict setObject:[result valueForKey:#"registeredEmail"] forKey:#"registeredEmail"];
[ADM.databaseResponseOfProfileDict setObject:[result valueForKey:#"role"] forKey:#"role"];
[ADM.databaseResponseOfProfileDict setObject:[result valueForKey:#"studentID"] forKey:#"studentID"];
NSLog(#"dic:%#",ADM.databaseResponseOfProfileDict);}
I have found a solution using Objective C. It runs, but I'm not sure that it is the correct solution.
- (void)dbManager {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
if ([context hasChanges] && ![context save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
abort();
}
NSManagedObject *customAnimal = [NSEntityDescription insertNewObjectForEntityForName:#"Animals" inManagedObjectContext:context];
[customAnimal setValue:#"Lion" forKey:#"type"];
[customAnimal setValue:#"Rabit" forKey:#"name"];
[customAnimal setValue:#"Blue" forKey:#"color"];
[customAnimal setValue:#12 forKey:#"age"];
NSLog(#"Get data from DB");
NSMutableArray* animalsArray;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Animals"];
animalsArray = [[context executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSLog(#"array is %#", animalsArray); // array is (
"<Animals: 0x6000000aee80> (entity: Animals; id: 0x60000022e120 <x-coredata:///Animals/tAAC7332D-6BEF-441C-9041-0ECB57469FA62> ; data: {\n age = 12;\n color = Blue;\n name = Rabit;\n type = Lion;\n})"
}
For all the beginners out there, this will give you the basic idea.
welcome.m
==========
#import "welcomepage.h"
#import "Register.h"
#import "login.h"
#import "AppDelegate.h"
#import "Student+CoreDataProperties.h"
#import "loginbtn.h"
#import "King+CoreDataProperties.h"
#interface welcomepage ()
{
AppDelegate *a;
NSManagedObjectContext *context;
}
#end
#implementation welcomepage
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (IBAction)login:(id)sender
{
loginbtn *lb=[[loginbtn alloc]init];
[self.navigationController pushViewController:lb animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)register:(id)sender
{
a=(AppDelegate *)[UIApplication sharedApplication].delegate;
NSManagedObjectContext *context1=((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;
Student *ss=[NSEntityDescription insertNewObjectForEntityForName:#"Student" inManagedObjectContext:context1];
ss.name=[NSString stringWithFormat:#"%#",_txtfld1.text];
ss.age=[NSString stringWithFormat:#"%#",_txtfld2.text];
ss.place=[NSString stringWithFormat:#"%#",_txtfld3.text];
[a saveContext];
if (_txtfld1.text.length && _txtfld2.text.length && _txtfld3.text.length != 0)
{
UIAlertView *al=[[UIAlertView alloc]initWithTitle:#"THANK YOU" message:#"DATA SUCESSFULLY SAVER. YOU CAN LOGIN NOW WITH YOUR PASSWORD AND NAME" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[al show];
_txtfld1.text=#"";
_txtfld2.text=#"";
_txtfld3.text=#"";
Register *rg=[[Register alloc]init];
[self.navigationController pushViewController:rg animated:YES];
}
else
{
UIAlertView *al2=[[UIAlertView alloc]initWithTitle:#"WARRNING" message:#"PLEASE FILL THE DATA COMPLETELY" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[al2 show];
}
}
===================================================
Register.m
==========
#import "Register.h"
#import "AppDelegate.h"
#import "Student+CoreDataProperties.h"
#import "welcomepage.h"
#interface Register ()<UITableViewDelegate,UITableViewDataSource>
{
AppDelegate *a;
NSManagedObjectContext *context01;
NSArray *array01;
}
#end
#implementation Register
- (void)viewDidLoad
{
[super viewDidLoad];
a=((AppDelegate *)[UIApplication sharedApplication].delegate);
context01=((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;
// specifying nsrequest and nsentity
NSFetchRequest *req=[[NSFetchRequest alloc]init];
NSEntityDescription *entity01=[NSEntityDescription entityForName:#"Student" inManagedObjectContext:context01];
[req setEntity:entity01];
// putting datas from reto array
NSError *err=nil;
array01=[context01 executeFetchRequest:req error:&err];
// Do any additional setup after loading the view from its nib.
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return array01.count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ci=#"hai";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ci];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ci];
}
if (indexPath.row==0) {
cell.textLabel.text=[[array01 objectAtIndex:indexPath.section]valueForKey:#"name"];
}
if (indexPath.row==1) {
cell.textLabel.text=[[array01 objectAtIndex:indexPath.section]valueForKey:#"age"];
}
if (indexPath.row==2) {
cell.textLabel.text=[[array01 objectAtIndex:indexPath.section]valueForKey:#"place"];
}
return cell;
}
==================================================
Loginbtn.m
============
#import "loginbtn.h"
#import "AppDelegate.h"
#import "Student+CoreDataProperties.h"
#import "login.h"
#interface loginbtn ()
{
AppDelegate *a;
NSArray *arraylb;
}
#end
#implementation loginbtn
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)lgbtn:(id)sender
{
a=(AppDelegate *)[UIApplication sharedApplication].delegate;
//xcode 8.2.1 specification code
NSManagedObjectContext *context=((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;
//creating feathch request and entity
NSFetchRequest *req=[[NSFetchRequest alloc]init];
NSEntityDescription *entity=[NSEntityDescription entityForName:#"Student" inManagedObjectContext:context];
[req setEntity:entity];
// setting predicate
NSPredicate *pre=[NSPredicate predicateWithFormat:#"age like %# and place like %#",_txt1.text,_txt2.text];
[req setPredicate:pre];
//creating error and array to store
NSError *err=nil;
arraylb=[[NSArray alloc]init];
arraylb=[context executeFetchRequest:req error:&err];
login *lg=[[login alloc]init];
if (arraylb.count!=0)
{
lg.array001=arraylb;
}
//
// if (arraylb.count!=0)
//// {
////
//// lv *lvi=[[lv alloc]init];
////
//// //passing value
//// lvi.array001=arraylb;
////
////
//// //lv.str1=self.tf1.text;
//// //lv.str2=self.tf2.text;
//// [self.navigationController pushViewController:lvi animated:YES];
////
////
//// }
//// else
//// {
//
// self.lb.text=#"Invalid username & password";
//
// }
//
[self.navigationController pushViewController:lg animated:YES];
}
=====================================================
Lohin.m
=========
#import "login.h"
#import "Student+CoreDataProperties.h"
#import "AppDelegate.h"
#import "loginbtn.h"
#interface login ()
{
AppDelegate *a;
NSArray *array01;
}
#end
#implementation login
- (void)viewDidLoad
{
[super viewDidLoad];
_txt11.text=[[_array001 objectAtIndex:0]valueForKey:#"name"];
_txt22.text=[[_array001 objectAtIndex:0]valueForKey:#"age"];
_txt33.text=[[_array001 objectAtIndex:0]valueForKey:#"place"];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
// Dispose of any resources that can be recreated.
}
I have an app that allows you to scan a QR code for meta data. The root view controller has two text fields, and allows you to fill one of those fields with the scanner. The button to access the scanner uses the "Show" segue to push the Scanning view onto the navigation stack.
My intention is that once a valid scan has been completed, the view controller will pass data back to the parent controller, and then be removed.
Being that the view has been pushed, I should be able to implement popViewControllerAnimated, but this does not work. I have also tried iterating through the view controllers in the navigation stack, matching the class I'm trying to pop to and using popToViewController, but am still stuck with the view that I'm trying to pop off the stack.
My viewcontroller.m
#interface ScanQRViewController ()
#end
#implementation ScanQRViewController
#synthesize scanPreview, scanPreviewLayer, scanSession, addyString, delegate;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
scanSession = nil;
[self startScanning];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark QR code scanning
-(void)startScanning {
addyString = nil;
NSError *error;
// create capture device and input
AVCaptureDevice *capDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:capDevice error:&error];
// error checking
if(!input) {
NSLog(#"%#", [error localizedDescription]);
}
// init the capture session
scanSession = [[AVCaptureSession alloc] init];
[scanSession addInput:input];
AVCaptureMetadataOutput *metaOutput = [[AVCaptureMetadataOutput alloc] init];
[scanSession addOutput:metaOutput];
// assign to dispatch queue
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("qrQueue", NULL);
[metaOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[metaOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
// create camera view for user
scanPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:scanSession];
[scanPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[scanPreviewLayer setFrame:scanPreview.layer.bounds];
[scanPreview.layer addSublayer:scanPreviewLayer];
// start running sesssion
[scanSession startRunning];
}
- (void)stopScanning {
[scanSession stopRunning];
scanSession = nil;
[scanPreviewLayer removeFromSuperlayer];
}
#pragma mark AV Delegate Methods
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
// check for objects
if (metadataObjects != nil && [metadataObjects count] > 0) {
//get the last object
AVMetadataMachineReadableCodeObject *metaObj = [metadataObjects objectAtIndex:0];
if([[metaObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
// remove url string if exists
if ([[[metaObj stringValue] substringToIndex:9] isEqualToString:#"zetacoin:"]) {
addyString = [[metaObj stringValue] substringFromIndex:9];
} else {
addyString = [metaObj stringValue];
}
}
[self stopScanning];
[self dismissView];
}
}
#pragma mark - Navigation
- (void)dismissView {
[delegate ScanQRCodeDidFinish:self];
[self.navigationController popViewControllerAnimated:YES];
}
#end
So I figured out the issue to this problem. Essentially when passing the data back to the parent controller to the delegate, I wasn't on the main thread. Therefore it would eventually timeout and return to the view, but very slowly. My two views:
QRScanner.m < The scanning view
#interface ScanQRViewController ()
#end
#implementation ScanQRViewController
#synthesize scanPreview, scanPreviewLayer, scanSession, addyString, delegate;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
scanSession = nil;
[self startScanning];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark QR code scanning
-(void)startScanning {
addyString = nil;
NSError *error;
// create capture device and input
AVCaptureDevice *capDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:capDevice error:&error];
// error checking
if(!input) {
NSLog(#"%#", [error localizedDescription]);
}
// init the capture session
scanSession = [[AVCaptureSession alloc] init];
[scanSession addInput:input];
AVCaptureMetadataOutput *metaOutput = [[AVCaptureMetadataOutput alloc] init];
[scanSession addOutput:metaOutput];
// assign to dispatch queue
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("qrQueue", NULL);
[metaOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[metaOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
// create camera view for user
scanPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:scanSession];
[scanPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[scanPreviewLayer setFrame:scanPreview.layer.bounds];
[scanPreview.layer addSublayer:scanPreviewLayer];
// start running sesssion
[scanSession startRunning];
}
- (void)stopScanning {
[scanSession stopRunning];
scanSession = nil;
[scanPreviewLayer removeFromSuperlayer];
}
#pragma mark AV Delegate Methods
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
// check for objects
if (metadataObjects != nil && [metadataObjects count] > 0) {
//get the last object
AVMetadataMachineReadableCodeObject *metaObj = [metadataObjects objectAtIndex:0];
if([[metaObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
// remove url string if exists
if ([[[metaObj stringValue] substringToIndex:9] isEqualToString:#"zetacoin:"]) {
addyString = [[metaObj stringValue] substringFromIndex:9];
} else {
addyString = [metaObj stringValue];
}
}
[self stopScanning];
[self dismissView];
}
}
#pragma mark - Navigation
- (void)dismissView {
NSLog(#"%#", self.navigationController);
[delegate ScanQRCodeDidFinish:self];
}
#end
AddAddress.m < The view I was trying to return to
#import "AddAddressViewController.h"
#import "ScanQRViewController.h"
#interface AddAddressViewController ()
#end
#implementation AddAddressViewController
#synthesize nameField, addressField, addressText;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.navigationItem.backBarButtonItem.title = #"Back";
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewWillAppear:(BOOL)animated {
// check to see if there's an address (QR) add to text field
if (addressText != nil) {
addressField.text = addressText;
NSLog(#"Address: %#", addressText); // debugging
}
}
#pragma mark delegate methods
- (void)ScanQRCodeDidFinish:(ScanQRViewController *)sqrvc {
if (![NSThread isMainThread]) {
dispatch_sync(dispatch_get_main_queue(), ^{
addressField.text = sqrvc.addyString;
[self.navigationController popViewControllerAnimated:YES];
});
} else {
addressField.text = sqrvc.addyString;
[self.navigationController popViewControllerAnimated:YES];
}
}
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
ScanQRViewController *sqvc = [segue destinationViewController];
sqvc.delegate = self;
}
#end
By adding the dispatch_sync(dispatch_get_main_queue(), ^{ it executed on the main thread and returned back the view as expected.
I started with xmppframework recently,but i am stuck with an issue.i am able to connect to my server on my local network but the xmppstreamdelegate methods are not getting called on my custom class,but works absolutely fine on appdelegate class .Can anyone pls help me on this.Is the delegate only supported on the appdelegate class ?
Header:
#interface XmppClass : NSObject<XMPPStreamDelegate>{
XMPPStream *xmppStream;
Login * loginDetail;
BOOL allowSelfSignedCertificates;
BOOL allowSSLHostNameMismatch;
}
#property (nonatomic, strong, readonly) XMPPStream *xmppStream;
#property (nonatomic, strong) Login *loginDetail;
- (id)initWithLogin:(Login *) loginrefernce;
- (BOOL)connect;
- (void)disconnect;
- (void)setupStream;
#end
Implementation:
#implementation XmppClass
#synthesize xmppStream;
#synthesize loginDetail;
- (id)initWithLogin:(Login *) loginrefernce
{
self = [super init];
if (self) {
self.loginDetail=loginrefernce;
[DDLog addLogger:[DDTTYLogger sharedInstance]];
[self setupStream];
[self connect];
}
return self;
}
- (void)setupStream
{
NSAssert(xmppStream == nil, #"Method setupStream invoked multiple times");
// Setup xmpp stream
//
// The XMPPStream is the base class for all activity.
// Everything else plugs into the xmppStream, such as modules/extensions and delegates.
xmppStream = [[XMPPStream alloc] init];
#if !TARGET_IPHONE_SIMULATOR
{
// Want xmpp to run in the background?
//
// P.S. - The simulator doesn't support backgrounding yet.
// When you try to set the associated property on the simulator, it simply fails.
// And when you background an app on the simulator,
// it just queues network traffic til the app is foregrounded again.
// We are patiently waiting for a fix from Apple.
// If you do enableBackgroundingOnSocket on the simulator,
// you will simply see an error message from the xmpp stack when it fails to set the property.
xmppStream.enableBackgroundingOnSocket = YES;
}
#endif
NSLog(#"setup stream");
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
[xmppStream setHostName:#"10.68.202.123"];
//[xmppStream setHostPort:8070];
allowSelfSignedCertificates = NO;
allowSSLHostNameMismatch = NO;
// You may need to alter these settings depending on the server you're connecting to
}
- (BOOL)connect
{
NSLog(#"connect");
if (![xmppStream isDisconnected]) {
return YES;
}
//
// If you don't want to use the Settings view to set the JID,
// uncomment the section below to hard code a JID and password.
//
// myJID = #"user#gmail.com/xmppframework";
// myPassword = #"";
if (self.loginDetail.emailId == nil || self.loginDetail.password == nil) {
return NO;
}
[xmppStream setMyJID:[XMPPJID jidWithString:[self.loginDetail.emailId stringByAppendingString:#"/pc"]]];
NSError *error = nil;
if (![xmppStream connect:&error])
{
NSLog(#"Error connecting: %#", error);
return NO;
}
return YES;
}
- (void)disconnect
{
[xmppStream disconnect];
}
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"some security thing");
if (allowSelfSignedCertificates)
{
[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
}
if (allowSSLHostNameMismatch)
{
[settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];
}
else
{
// Google does things incorrectly (does not conform to RFC).
// Because so many people ask questions about this (assume xmpp framework is broken),
// I've explicitly added code that shows how other xmpp clients "do the right thing"
// when connecting to a google server (gmail, or google apps for domains).
NSString *expectedCertName = nil;
NSString *serverDomain = xmppStream.hostName;
NSString *virtualDomain = [xmppStream.myJID domain];
if ([serverDomain isEqualToString:#"talk.google.com"])
{
if ([virtualDomain isEqualToString:#"gmail.com"])
{
expectedCertName = virtualDomain;
}
else
{
expectedCertName = serverDomain;
}
}
else if (serverDomain == nil)
{
expectedCertName = virtualDomain;
}
else
{
expectedCertName = serverDomain;
}
if (expectedCertName)
{
[settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}
}
}
- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"connected");
NSError *error = nil;
if (![[self xmppStream] authenticateWithPassword:self.loginDetail.password error:&error])
{
DDLogError(#"Error authenticating: %#", error);
}
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"authenticated");
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"did not authenticate");
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
return NO;
}
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
// A simple example of inbound message handling.
}
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
DDLogVerbose(#"%#: %# - %#", THIS_FILE, THIS_METHOD, [presence fromStr]);
}
- (void)xmppStream:(XMPPStream *)sender didReceiveError:(id)error
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"%#",error);
}
#end
Most probably the problem is that your class instance, that is a delegate for your XMPPStream is released before the delegate method is called on it. Make it more persistent by making this class a property or instance variable of other class or by using dispatch_once. For example,
Change
YourClass *instance = [[YourClass alloc] init];
instance.xmppStream = ....
by
#property(nonatomic, strong) YourClass *instance;
self.instance = [[YourClass alloc] init];
self.instance.xmppStream = ....
Here YourClass contains XMPPStream and is delegate for it.
I've written a big blog post on this problem. This is pretty common situation.
http://blog.alwawee.com/2013/07/31/on-xmppframework-delegate-method-not-being-called/
you can use the multicast,sth like this
[[self appDelegate].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
I had same problem... this helped me. Hope it works for you, just make following Changes in your code.
Static XmppClass *selfRef = nil;
#implementation XmppClass
#synthesize xmppStream;
- (void)setupStream
{
// Setup xmpp stream
selfRef = [[XmppClass alloc] init];
xmppStream = [[XMPPStream alloc] init];
[xmppStream addDelegate:selfRef delegateQueue:dispatch_get_main_queue()];
Do you know any way / method to take a photo in iOS and saving it to camera Roll only with a simple button pressure without showing any preview?
I already know how to show the camera view but it show the preview of the image and the user need to click the take photo button to take the photo.
In few Words: the user click the button, the picture is taken, without previews nor double checks to take / save the photo.
I already found the takePicture method of UIIMagePickerController Class http://developer.apple.com/library/ios/documentation/uikit/reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html#//apple_ref/occ/instm/UIImagePickerController/takePicture
Set the showsCameraControls-Property to NO.
poc = [[UIImagePickerController alloc] init];
[poc setTitle:#"Take a photo."];
[poc setDelegate:self];
[poc setSourceType:UIImagePickerControllerSourceTypeCamera];
poc.showsCameraControls = NO;
You also have to add your own Controls as a custom view on the top of poc.view. But that is very simple and you can add your own UI-style by that way.
You receive the image-data as usually within the imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:
To take the photo, you call
[poc takePicture];
from your custom button.
Hope, that works for you.
Assuming you want a point-and-shoot method, you can create an AVSession and just call the UIImageWriteToSavedPhotosAlbum method.
Here is a link that goes into that exact process: http://www.musicalgeometry.com/?p=1297
It's also worth noting that your users need to have given the app access to their camera roll or you may experience issues saving the images.
You need to design your own custom preview according to your size, on capture button pressed and call buttonPressed method and do stuff what you want
(void)buttonPressed:(UIButton *)sender {
NSLog(#" Capture Clicked");
[self.imagePicker takePicture];
//[NSTimer scheduledTimerWithTimeInterval:3.0f target:self
selector:#selector(timerFired:) userInfo:nil repeats:NO];
}
following is code that will take photo without showing preview screen. when i tried the accepted answer, which uses UIImagePickerController, the preview screen showed, then auto disappeared. with the code below, user taps 'takePhoto' button, and the devices takes photo with zero change to UI (in my app, i add a green check mark next to take photo button). the code below is from apple https://developer.apple.com/LIBRARY/IOS/samplecode/AVCam/Introduction/Intro.html with the 'extra functions' (that do not relate to taking still photo) commented out. thank you incmiko for suggesting this code in your answer iOS take photo from camera without modalViewController.
updating code, 26 mar 2015:
to trigger snap photo:
[self snapStillImage:sender];
in .h file:
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
// include code below in header file, after #import and before #interface
// avfoundation copy paste code
static void * CapturingStillImageContext = &CapturingStillImageContext;
static void * RecordingContext = &RecordingContext;
static void * SessionRunningAndDeviceAuthorizedContext = &SessionRunningAndDeviceAuthorizedContext;
// avfoundation, include code below after #interface
// avf - Session management.
#property (nonatomic) dispatch_queue_t sessionQueue; // Communicate with the session and other session objects on this queue.
#property (nonatomic) AVCaptureSession *session;
#property (nonatomic) AVCaptureDeviceInput *videoDeviceInput;
#property (nonatomic) AVCaptureMovieFileOutput *movieFileOutput;
#property (nonatomic) AVCaptureStillImageOutput *stillImageOutput;
// avf - Utilities.
#property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
#property (nonatomic, getter = isDeviceAuthorized) BOOL deviceAuthorized;
#property (nonatomic, readonly, getter = isSessionRunningAndDeviceAuthorized) BOOL sessionRunningAndDeviceAuthorized;
#property (nonatomic) BOOL lockInterfaceRotation;
#property (nonatomic) id runtimeErrorHandlingObserver;
in .m file:
#pragma mark - AV Foundation
- (BOOL)isSessionRunningAndDeviceAuthorized
{
return [[self session] isRunning] && [self isDeviceAuthorized];
}
+ (NSSet *)keyPathsForValuesAffectingSessionRunningAndDeviceAuthorized
{
return [NSSet setWithObjects:#"session.running", #"deviceAuthorized", nil];
}
// call following method from viewDidLoad
- (void)CreateAVCaptureSession
{
// Create the AVCaptureSession
AVCaptureSession *session = [[AVCaptureSession alloc] init];
[self setSession:session];
// Check for device authorization
[self checkDeviceAuthorizationStatus];
// In general it is not safe to mutate an AVCaptureSession or any of its inputs, outputs, or connections from multiple threads at the same time.
// Why not do all of this on the main queue?
// -[AVCaptureSession startRunning] is a blocking call which can take a long time. We dispatch session setup to the sessionQueue so that the main queue isn't blocked (which keeps the UI responsive).
dispatch_queue_t sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL);
[self setSessionQueue:sessionQueue];
dispatch_async(sessionQueue, ^{
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
NSError *error = nil;
AVCaptureDevice *videoDevice = [ViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionFront];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if (error)
{
NSLog(#"%#", error);
}
if ([session canAddInput:videoDeviceInput])
{
[session addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
dispatch_async(dispatch_get_main_queue(), ^{
// Why are we dispatching this to the main queue?
// Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and UIView can only be manipulated on main thread.
// Note: As an exception to the above rule, it is not necessary to serialize video orientation changes on the AVCaptureVideoPreviewLayer’s connection with other session manipulation.
});
}
/* AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
if (error)
{
NSLog(#"%#", error);
}
if ([session canAddInput:audioDeviceInput])
{
[session addInput:audioDeviceInput];
}
*/
AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([session canAddOutput:movieFileOutput])
{
[session addOutput:movieFileOutput];
AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
if ([connection isVideoStabilizationSupported])
[connection setEnablesVideoStabilizationWhenAvailable:YES];
[self setMovieFileOutput:movieFileOutput];
}
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
if ([session canAddOutput:stillImageOutput])
{
[stillImageOutput setOutputSettings:#{AVVideoCodecKey : AVVideoCodecJPEG}];
[session addOutput:stillImageOutput];
[self setStillImageOutput:stillImageOutput];
}
});
}
// call method below from viewWilAppear
- (void)AVFoundationStartSession
{
dispatch_async([self sessionQueue], ^{
[self addObserver:self forKeyPath:#"sessionRunningAndDeviceAuthorized" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:SessionRunningAndDeviceAuthorizedContext];
[self addObserver:self forKeyPath:#"stillImageOutput.capturingStillImage" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:CapturingStillImageContext];
[self addObserver:self forKeyPath:#"movieFileOutput.recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
__weak ViewController *weakSelf = self;
[self setRuntimeErrorHandlingObserver:[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureSessionRuntimeErrorNotification object:[self session] queue:nil usingBlock:^(NSNotification *note) {
ViewController *strongSelf = weakSelf;
dispatch_async([strongSelf sessionQueue], ^{
// Manually restarting the session since it must have been stopped due to an error.
[[strongSelf session] startRunning];
});
}]];
[[self session] startRunning];
});
}
// call method below from viewDidDisappear
- (void)AVFoundationStopSession
{
dispatch_async([self sessionQueue], ^{
[[self session] stopRunning];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
[[NSNotificationCenter defaultCenter] removeObserver:[self runtimeErrorHandlingObserver]];
[self removeObserver:self forKeyPath:#"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext];
[self removeObserver:self forKeyPath:#"stillImageOutput.capturingStillImage" context:CapturingStillImageContext];
[self removeObserver:self forKeyPath:#"movieFileOutput.recording" context:RecordingContext];
});
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (BOOL)shouldAutorotate
{
// Disable autorotation of the interface when recording is in progress.
return ![self lockInterfaceRotation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// [[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == CapturingStillImageContext)
{
BOOL isCapturingStillImage = [change[NSKeyValueChangeNewKey] boolValue];
if (isCapturingStillImage)
{
[self runStillImageCaptureAnimation];
}
}
else if (context == RecordingContext)
{
BOOL isRecording = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRecording)
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setTitle:NSLocalizedString(#"Stop", #"Recording button stop title") forState:UIControlStateNormal];
// [[self recordButton] setEnabled:YES];
}
else
{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setTitle:NSLocalizedString(#"Record", #"Recording button record title") forState:UIControlStateNormal];
// [[self recordButton] setEnabled:YES];
}
});
}
else if (context == SessionRunningAndDeviceAuthorizedContext)
{
BOOL isRunning = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRunning)
{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setEnabled:YES];
// [[self stillButton] setEnabled:YES];
}
else
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setEnabled:NO];
// [[self stillButton] setEnabled:NO];
}
});
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark Actions
- (IBAction)toggleMovieRecording:(id)sender
{
// [[self recordButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
if (![[self movieFileOutput] isRecording])
{
[self setLockInterfaceRotation:YES];
if ([[UIDevice currentDevice] isMultitaskingSupported])
{
// Setup background task. This is needed because the captureOutput:didFinishRecordingToOutputFileAtURL: callback is not received until AVCam returns to the foreground unless you request background execution time. This also ensures that there will be time to write the file to the assets library when AVCam is backgrounded. To conclude this background execution, -endBackgroundTask is called in -recorder:recordingDidFinishToOutputFileURL:error: after the recorded file has been saved.
[self setBackgroundRecordingID:[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]];
}
// Update the orientation on the movie file output video connection before starting recording.
// [[[self movieFileOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Turning OFF flash for video recording
[ViewController setFlashMode:AVCaptureFlashModeOff forDevice:[[self videoDeviceInput] device]];
// Start recording to a temporary file.
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[#"movie" stringByAppendingPathExtension:#"mov"]];
[[self movieFileOutput] startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
}
else
{
[[self movieFileOutput] stopRecording];
}
});
}
- (IBAction)changeCamera:(id)sender
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setEnabled:NO];
// [[self stillButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *currentVideoDevice = [[self videoDeviceInput] device];
AVCaptureDevicePosition preferredPosition = AVCaptureDevicePositionUnspecified;
AVCaptureDevicePosition currentPosition = [currentVideoDevice position];
switch (currentPosition)
{
case AVCaptureDevicePositionUnspecified:
preferredPosition = AVCaptureDevicePositionBack;
break;
case AVCaptureDevicePositionBack:
preferredPosition = AVCaptureDevicePositionFront;
break;
case AVCaptureDevicePositionFront:
preferredPosition = AVCaptureDevicePositionBack;
break;
}
AVCaptureDevice *videoDevice = [ViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:preferredPosition];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
[[self session] beginConfiguration];
[[self session] removeInput:[self videoDeviceInput]];
if ([[self session] canAddInput:videoDeviceInput])
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:currentVideoDevice];
[ViewController setFlashMode:AVCaptureFlashModeAuto forDevice:videoDevice];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:videoDevice];
[[self session] addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
}
else
{
[[self session] addInput:[self videoDeviceInput]];
}
[[self session] commitConfiguration];
dispatch_async(dispatch_get_main_queue(), ^{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setEnabled:YES];
// [[self stillButton] setEnabled:YES];
});
});
}
- (IBAction)snapStillImage:(id)sender
{
dispatch_async([self sessionQueue], ^{
// Update the orientation on the still image output video connection before capturing.
// [[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Flash set to Auto for Still Capture
[ViewController setFlashMode:AVCaptureFlashModeAuto forDevice:[[self videoDeviceInput] device]];
// Capture a still image.
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer)
{
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
// do someting good with saved image
[self saveImageToParse:image];
}
}];
});
}
- (IBAction)focusAndExposeTap:(UIGestureRecognizer *)gestureRecognizer
{
// CGPoint devicePoint = [(AVCaptureVideoPreviewLayer *)[[self previewView] layer] captureDevicePointOfInterestForPoint:[gestureRecognizer locationInView:[gestureRecognizer view]]];
// [self focusWithMode:AVCaptureFocusModeAutoFocus exposeWithMode:AVCaptureExposureModeAutoExpose atDevicePoint:devicePoint monitorSubjectAreaChange:YES];
}
- (void)subjectAreaDidChange:(NSNotification *)notification
{
CGPoint devicePoint = CGPointMake(.5, .5);
[self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposeWithMode:AVCaptureExposureModeContinuousAutoExposure atDevicePoint:devicePoint monitorSubjectAreaChange:NO];
}
#pragma mark File Output Delegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
if (error)
NSLog(#"%#", error);
[self setLockInterfaceRotation:NO];
// Note the backgroundRecordingID for use in the ALAssetsLibrary completion handler to end the background task associated with this recording. This allows a new recording to be started, associated with a new UIBackgroundTaskIdentifier, once the movie file output's -isRecording is back to NO — which happens sometime after this method returns.
UIBackgroundTaskIdentifier backgroundRecordingID = [self backgroundRecordingID];
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
[[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
if (error)
NSLog(#"%#", error);
[[NSFileManager defaultManager] removeItemAtURL:outputFileURL error:nil];
if (backgroundRecordingID != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask:backgroundRecordingID];
}];
}
#pragma mark Device Configuration
- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange
{
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *device = [[self videoDeviceInput] device];
NSError *error = nil;
if ([device lockForConfiguration:&error])
{
if ([device isFocusPointOfInterestSupported] && [device isFocusModeSupported:focusMode])
{
[device setFocusMode:focusMode];
[device setFocusPointOfInterest:point];
}
if ([device isExposurePointOfInterestSupported] && [device isExposureModeSupported:exposureMode])
{
[device setExposureMode:exposureMode];
[device setExposurePointOfInterest:point];
}
[device setSubjectAreaChangeMonitoringEnabled:monitorSubjectAreaChange];
[device unlockForConfiguration];
}
else
{
NSLog(#"%#", error);
}
});
}
+ (void)setFlashMode:(AVCaptureFlashMode)flashMode forDevice:(AVCaptureDevice *)device
{
if ([device hasFlash] && [device isFlashModeSupported:flashMode])
{
NSError *error = nil;
if ([device lockForConfiguration:&error])
{
[device setFlashMode:flashMode];
[device unlockForConfiguration];
}
else
{
NSLog(#"%#", error);
}
}
}
+ (AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
AVCaptureDevice *captureDevice = [devices firstObject];
for (AVCaptureDevice *device in devices)
{
if ([device position] == position)
{
captureDevice = device;
break;
}
}
return captureDevice;
}
#pragma mark UI
- (void)runStillImageCaptureAnimation
{
/*
dispatch_async(dispatch_get_main_queue(), ^{
[[[self previewView] layer] setOpacity:0.0];
[UIView animateWithDuration:.25 animations:^{
[[[self previewView] layer] setOpacity:1.0];
}];
});
*/
}
- (void)checkDeviceAuthorizationStatus
{
NSString *mediaType = AVMediaTypeVideo;
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
if (granted)
{
//Granted access to mediaType
[self setDeviceAuthorized:YES];
}
else
{
//Not granted access to mediaType
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:#"AVCam!"
message:#"AVCam doesn't have permission to use Camera, please change privacy settings"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
[self setDeviceAuthorized:NO];
});
}
}];
}
My simple iphone app is crashing on launch, it says "the application downloadText quit unexcpectedly" None of these windows that pop up when a mac app crashes and has a send to Apple button. My .h is below and I would greatly appreciate it if anyone could give me a hand as to what's wrong?
#import "downloadTextViewController.h"
#implementation downloadTextViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSString *myPath = [self saveFilePath];
NSLog(myPath);
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists)
{
NSArray *values = [[NSArray alloc] initWithContentsOfFile:myPath];
textView.text = [values objectAtIndex:0];
[values release];
}
// notification
UIApplication *myApp = [UIApplication sharedApplication];
// add yourself to the dispatch table
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:myApp];
[super viewDidLoad];
}
- (IBAction)fetchData {
/// Show activityIndicator / progressView
NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://simpsonatyapps.com/exampletext.txt"]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:1.0];
NSURLConnection *downloadConnection = [[NSURLConnection alloc] initWithRequest:downloadRequest delegate:self];
if (downloadConnection)
downloadedData = [[NSMutableData data] retain];
else {
/// Error message
}
}
- (void)connection:(NSURLConnection *)downloadConnection didReceiveData:(NSData *)data {
[downloadedData appendData:data];
NSString *file = [[NSString alloc] initWithData:downloadedData encoding:NSUTF8StringEncoding];
textView.text = file;
/// Remove activityIndicator / progressView
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:1];
}
- (NSString *) saveFilePath
{
NSArray *pathArray =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[pathArray objectAtIndex:0] stringByAppendingPathComponent:#"savedddata.plist"];
}
- (void)applicationWillTerminate:(UIApplication *)application {
NSArray *values = [[NSArray alloc] initWithObjects:textView.text,nil];
[values writeToFile:[self saveFilePath] atomically:YES];
[values release];
}
- (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 {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil;
}
#end
Edit:
The console comes up with:
21/03/10 2:32:19 PM downloadText[3548] Stack:
( 8307803, 2474450491, 8466881, 2787944, 2786485, 25429108, 8210735, 25423659,
25431927, 24117515, 24111079, 24110797, 8337, 23594443, 23632310, 23620404,
23602815, 23629921, 134489, 8092544, 8088648, 23596565, 23633839, 8252 )
Check the Console for exception reports. [Spotlight search for "Console" application if you're lazy. ;-] Any stack trace there to provide clues?
Run in the simulator in debug mode. Set a breakpoint at the start of viewDidLoad, plus anywhere in your code from any stack trace left in the Console.
Does putting the call to "[super viewDidLoad]" first (instead of last) help? If that's doing any work, it might be tripping up your viewDidLoad. Check the Console output first though -- I tend to make code changes only when I understand what's going wrong, or I can use it to rule out potential causes.