My iOS Daemon does not receive call state updates, although a handler inline method is defined. It seems to me, that the program does not enter the event loop. does anyone of you have any experience with daemons on iOS, and if yes, can you help me? Here is what i got (compiling it with the appropriate compiler, linking it against necessary libraries and frameworks):
#interface CLAppDelegate : NSObject<UIApplicationDelegate>{
}
#end
#implementation CLAppDelegate
- (id) init
{
self = [super init];
if (self != nil)
{
NSLog(#"AppDelegate created!");
return self;
}
NSLog(#"Somehow i lost my pants.");
return nil;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(#"Application launched.");
CTCallCenter* callCenter = [[CTCallCenter alloc]init];
callCenter.callEventHandler = ^(CTCall* inCTCall) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"CallState: %#", [inCTCall callState]);
});
};
return YES;
}
#end
int main(int argc, char* argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Hello iPhone! (with app delegate)");
NSString* _appdelegateclassname = NSStringFromClass([CLAppDelegate class]);
NSLog(#"AppDelegate class name: %#", _appdelegateclassname);
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:#"http://www.smr.name"]];
int retVal = UIApplicationMain(argc, argv, nil, _appdelegateclassname);
[pool release];
return retVal;
}
It compiles and links, and even runs (OpenSSH to iPhone) - but the CallState log is never displayed.
Oh, and also, is there any possibility to run another application (in the /User/Applications/ folder) from that daemon?
Related
I have a sample app that uses AudioKit to record audio and display a waveform of that audio data. This sample app has two viewControllers with the root vc being a blank page with a button that will take the user to the audio recording page.
For some reason, only on iPhone X (iOS 11.4.1), while recording audio, if I hit the back button on the navigation bar (top left) and then try to go and record again the app will crash.
Specifically the app appears to crash when the recorder's method appendDataFromBufferList: withBufferSize: calls ExtAudioFileWrite(self.info->extAudioFileRef, bufferSize, bufferList). The error message that is printed in the console is:
testAudioCrash(1312,0x16e203000) malloc: * **error for object 0x109803a00: incorrect checksum for freed object - object was probably modified after being freed.
* **set a breakpoint in malloc_error_break to debug
I've gone through zombie profiling, leak profiling, stepped through the logic and the stack but I can't seem to figure out why this is happening.
Below i've provided the code for the test app as well as screenshots of the stack and the console output. Any help with figuring out why this is crashing would be greatly appreciated. Unfortunately the fact that this crash is also not 100% reproducible makes it a little more obscure to me.
Notes for code below:
There is no custom code in the .h files so I have not provided that. There are xib files for each view controller with the UI components for this. They're pretty simple so I have not provided information on those as well though I have no problem in providing any information on them, that anyone requests. I can also zip up the project and share that if anyone feels it's necessary.
Repro steps:
1) launch app
2) tap on record Audio button
3) tap on record button
4) hit back button on navigation bar
5) repeat steps 2-4 until crash happens
AppDelegate.m code:
#import "AppDelegate.h"
#import "testViewController.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
testViewController* rootVC = [[testViewController alloc] initWithNibName: #"testViewController" bundle: NSBundle.mainBundle];
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController: rootVC];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
testViewController.m code:
#import "testViewController.h"
#import "testSecondViewController.h"
#interface testViewController ()
#end
#implementation testViewController
- (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)AudioRecording:(id)sender
{
testSecondViewController* sVC = [[testSecondViewController alloc] initWithNibName: #"testSecondViewController" bundle: NSBundle.mainBundle];
[self.navigationController pushViewController: sVC animated: YES];
}
#end
testSecondViewController.m code:
#import "testSecondViewController.h"
#import AudioKit;
#import AudioKitUI;
#interface testSecondViewController () <EZMicrophoneDelegate, EZRecorderDelegate>
#property (nonatomic, strong) EZRecorder* recorder;
#property (nonatomic, strong) EZMicrophone* mic;
#property (nonatomic, strong) EZAudioPlayer* player;
#property (strong, nonatomic) IBOutlet EZAudioPlot *audioPlot;
#property (nonatomic, strong) NSURL *finishedRecordingURL;
#property (atomic, assign) BOOL isRecording;
#end
#implementation testSecondViewController
- (void)dealloc
{
if(_isRecording) [self pauseRecording: _mic];
if(_recorder) [self finalizeAudioFile: _recorder];
_recorder.delegate = nil;
_mic.delegate = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[EZAudioUtilities setShouldExitOnCheckResultFail: NO];
[self setupUI];
[self setupConfig];
[self audioKitSetup];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark UI Methods
-(void)setupUI
{
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style: UIBarButtonItemStylePlain target: nil action:#selector(cancelButtonClicked)];
[self configureWaveFormViewForAudioInput];
}
-(void)setupConfig
{
[self initializeMic];
[self initializeRecorder];
}
-(void)initializeMic
{
self.mic = [[EZMicrophone alloc] initWithMicrophoneDelegate: self];
self.isRecording = NO;
}
-(void)initializeRecorder
{
NSURL *fileUrl = [self testFilePathURL];
self.finishedRecordingURL = fileUrl;
self.recorder = [[EZRecorder alloc] initWithURL: fileUrl clientFormat: [self.mic audioStreamBasicDescription] fileType: EZRecorderFileTypeM4A delegate: self];
}
#pragma mark - Utils
- (NSArray *)applicationDocuments
{
return NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
}
- (NSString *)applicationDocumentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
- (NSURL *)testFilePathURL
{
self.finishedRecordingURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#",
[self applicationDocumentsDirectory],
#"test2.m4a"]];
if (self.finishedRecordingURL && [[NSFileManager defaultManager] fileExistsAtPath:self.finishedRecordingURL.path])
{
NSError *error;
[[NSFileManager defaultManager] removeItemAtURL:self.finishedRecordingURL error:&error];
if(error){
printf("%s", error.description);
}
}
return self.finishedRecordingURL;
}
#pragma mark AudioKit Util methods
- (void) audioKitSetup
{
[AKSettings setDefaultToSpeaker: YES];
[AKSettings setAudioInputEnabled: YES];
[AKSettings setPlaybackWhileMuted: YES];
[AKSettings setSampleRate: 44100];
[AKSettings setChannelCount: 1];
}
- (void) configureWaveFormViewForAudioInput
{
// self.audioPlot.gain = 6;
// self.audioPlot.color = [UIColor blueColor];
self.audioPlot.plotType = EZPlotTypeRolling;
// self.audioPlot.shouldFill = YES;
// self.audioPlot.shouldMirror = YES;
[self.view addSubview: self.audioPlot];
self.audioPlot.clipsToBounds = YES;
}
- (IBAction)startRecording:(id)sender
{
if (!self.mic)
{
self.mic = [EZMicrophone microphoneWithDelegate: self];
}
if (!self.recorder)
{
if (self.finishedRecordingURL && [[NSFileManager defaultManager] fileExistsAtPath:self.finishedRecordingURL.path])
{
self.recorder = [EZRecorder recorderWithURL: self.finishedRecordingURL clientFormat: [self.mic audioStreamBasicDescription] fileType: EZRecorderFileTypeM4A delegate: self];
}
else
{
self.recorder = [EZRecorder recorderWithURL: [self testFilePathURL] clientFormat: [self.mic audioStreamBasicDescription] fileType: EZRecorderFileTypeM4A delegate: self];
self.finishedRecordingURL = self.recorder.url;
}
}
[self.mic startFetchingAudio];
self.isRecording = YES;
}
- (IBAction)pauseRecording:(id)sender
{
[self.mic stopFetchingAudio];
self.isRecording = NO;
}
- (void) finalizeAudioFile: (EZRecorder*) recorder
{
if (self.isRecording)
{
[self.mic stopFetchingAudio];
}
[recorder closeAudioFile];
}
- (IBAction)cancelButtonClicked:(id)sender
{
if(self.isRecording)
{
[self pauseRecording: self.mic];
}
UIAlertController *alert = [UIAlertController alertControllerWithTitle: #"Delete recording?" message:#"Would you like to delete your audio recording and stop recording?" preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction* yesButton = [UIAlertAction
actionWithTitle:#"Discard"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self finalizeAudioFile: self.recorder];
NSError *error;
[[NSFileManager defaultManager] removeItemAtURL:self.finishedRecordingURL error:&error];
if(error){
printf("%s", error.description);
}
[self dismissViewControllerAnimated:YES completion:NULL];
}];
UIAlertAction* noButton = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[alert dismissViewControllerAnimated:YES completion: nil];
}];
[alert addAction:yesButton];
[alert addAction:noButton];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark - EZMicrophone Delegate methods
- (void) microphone:(EZMicrophone *)microphone
hasAudioReceived:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
{
__weak typeof (self) weakling = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakling.audioPlot updateBuffer:buffer[0]
withBufferSize:bufferSize];
});
}
- (void) microphone:(EZMicrophone *)microphone
hasBufferList:(AudioBufferList *)bufferList
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
{
if (self.isRecording)
{
[self.recorder appendDataFromBufferList:bufferList
withBufferSize:bufferSize];
}
}
- (void)microphone:(EZMicrophone *)microphone changedPlayingState:(BOOL)isPlaying
{
self.isRecording = isPlaying;
}
#end
images:
In my application, I am sending screenshot of the current view programmatically and sending to a socket server program at every 5 seconds interval.
Socket program is running in Eclipse. I checked the code earlier and able to send screenshot of the image to the socket without any issues.
After that, as per my actual requirement, I added a tab bar controller (5 tabs) and used navigation controller for the first tab selection. As per my code below, the first tab bar item is “MyHomeViewController”.
In the “MyHomeViewController” i have a button action called -(IBAction)goAhead:(id)sender. Clicking on this will take to another “HomeViewController”.
In this “HomeViewController”, I connect socket and if the socket connection is success, under “NSStreamEventHasSpaceAvailable” delegate method, i call a function called “[self coShareScreen];” to take to sending screenshot images of the current view (whatever view controller is present) and sending to that socket server program.
I use a “CobrowseSingletonSocket” class, where i have socket related variables and sending screenshot programmatically are handled in this function “-(void) takeScreenshotSend :(NSString *) endOrCancelString”.
My issue is, socket is getting connected successfully now. It should send screenshot of the image programmatically wherever the view I’m currently in.
As expected, Its start sending the screenshot of the view programmatically to socket server successfully at every 5 seconds interval.
But,
As its a navigation controller based view, If i coming back to the first view manually, which is “MyHomeViewController”. It tries to send that screen also, but it crashes after immediately write socket is done.
It is crashing immediately after writing here-> “int num = [self.outputStream write:[data bytes] maxLength:([data length])];”
This is crash is happening only if i come back in navigation controller manually. If i stay in “HomeViewController” itself after socket connection, it keeps sending screenshot programmatically a t every 5 seconds interval to socket server without any issues.
I don’t understand what could be the reason here? Please someone advise me, as i’m unable to fix this for long time. Please also let me know if i need to paste any more code here.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
UITabBarController *tabbarCtrler = [[UITabBarController alloc]init];
MyHomeViewController *myHomeCtrler = [[MyHomeViewController alloc] initWithNibName:#"MyHomeViewController" bundle:NULL];
[myHomeCtrler.tabBarItem setTitle:#"My Home"];
ProductsViewController *prodViewCtrler = [[ProductsViewController alloc] initWithNibName:#"ProductsViewController" bundle:NULL];
[prodViewCtrler.tabBarItem setTitle:#"Products"];
InboxViewController *inboxViewCtrler = [[InboxViewController alloc] initWithNibName:#"InboxViewController" bundle:NULL];
[inboxViewCtrler.tabBarItem setTitle:#"Inbox"];
ContactUSViewController *contactViewCtrler = [[ContactUSViewController alloc] initWithNibName:#"ContactUSViewController" bundle:NULL];
[contactViewCtrler.tabBarItem setTitle:#"Contact Us"];
VoiceViewController *voiceViewCtrler = [[VoiceViewController alloc] initWithNibName:#"VoiceViewController" bundle:NULL];
[voiceViewCtrler.tabBarItem setTitle:#"Voice"];
UINavigationController *navigationcontroller = [[UINavigationController alloc] initWithRootViewController:myHomeCtrler];
navigationcontroller.title = #"My News;
[navigationcontroller.navigationBar setBackgroundImage:[UIImage imageNamed:#"SettingsTitlebar.png"] forBarMetrics:UIBarMetricsDefault];
[navigationcontroller setNavigationBarHidden:YES];
//create an array of all view controllers that will represent the tab at the bottom
NSArray *arrayViewControllers = [[NSArray alloc] initWithObjects:
navigationcontroller, prodViewCtrler, inboxViewCtrler, contactViewCtrler, voiceViewCtrler, nil];
[tabbarCtrler setViewControllers:arrayViewControllers];
[self.window makeKeyAndVisible];
[self.window setRootViewController:tabbarCtrler];
return YES;
}
and
#import "MyHomeViewController.h"
#import "SettingsViewController.h"
#interface MyHomeViewController ()
#end
#implementation MyHomeViewController
- (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 from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)goAhead:(id)sender
{
HomeViewController *homeViewController = [[HomeViewController alloc] initWithNibName:#"HomeViewController" bundle:nil];
[self.navigationController pushViewController:setttingsViewController animated:YES];
}
and
// HomeViewController.m
//
//
#import "HomeViewController.h"
#import "AppDelegate.h"
#import "CobrowseSingletonSocket.h"
#import <QuartzCore/QuartzCore.h>
#import <notify.h>
#interface HomeViewController ()
#end
#implementation HomeViewController
#synthesize authTexField;
#synthesize sessionID;
#synthesize sentPing;
#synthesize bScreenOff;
#synthesize responseAlertView;
#synthesize portFld;
#synthesize ipFld;
#synthesize shareScreenTimer;
- (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 from its nib.
authTexField.delegate = self;
responseAlertView.delegate = self;
ipFld.delegate = self;
portFld.delegate = self;
bScreenOff = NO;
cobrowseSingletonIns = [CobrowseSingletonSocket sharedCobrowseSocketInstance];
}
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)connectShare:(id)sender
{
// Connect socket freshly here
[self initSocketConnection];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
- (IBAction)backAction:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
#pragma mark Socket Connection
- (void)initSocketConnection
{
NSString * ipAddrStr = ipFld.text;
NSString * portStr = portFld.text;
NSLog(#"IPAddress: %# ; Port: %#", ipAddrStr, portStr);
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
NSString *ipaddress = ipAddrStr;
ipaddress = [ipaddress stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"Retrieved socket ip: %#", cobrowseSingletonIns.socketIPAddress);
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)ipaddress, 8081, &readStream, &writeStream);
cobrowseSingletonIns.inputStream = (__bridge_transfer NSInputStream *)readStream;
cobrowseSingletonIns.outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[cobrowseSingletonIns.inputStream setDelegate:self];
[cobrowseSingletonIns.outputStream setDelegate:self];
[cobrowseSingletonIns.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[cobrowseSingletonIns.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[cobrowseSingletonIns.inputStream open];
[cobrowseSingletonIns.outputStream open];
}
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSString *io;
if (theStream == cobrowseSingletonIns.inputStream) io = #">>";
else io = #"<<";
NSLog(#"Stream space : %d",[cobrowseSingletonIns.outputStream hasSpaceAvailable]);
NSString *event;
switch (streamEvent)
{
case NSStreamEventNone:
event = #"NSStreamEventNone";
//statusText.text = #"Can not connect to the host!";
NSLog(#"NSStreamEventNone - Can not connect to the host");
break;
case NSStreamEventOpenCompleted:
event = #"NSStreamEventOpenCompleted";
//pingButton.hidden = NO;
//statusText.text = #"Connected";
NSLog(#"Connected");
break;
case NSStreamEventHasBytesAvailable:
event = #"NSStreamEventHasBytesAvailable";
NSLog(#"NSStreamEventHasBytesAvailable called");
if (theStream == cobrowseSingletonIns.inputStream)
{
//read data
//uint8_t buffer[1024];
uint8_t buffer[2];
NSMutableData *data=[[NSMutableData alloc] init];
int len;
while ([cobrowseSingletonIns.inputStream hasBytesAvailable])
{
len = [cobrowseSingletonIns.inputStream read:buffer maxLength:sizeof(buffer)];
if(len)
{
[data appendBytes:&buffer length:len];
}
else
{
NSLog(#"no buffer!");
}
}
NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
responseStr = [responseStr stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//do something with data
NSLog(#"Server said this-> %#", responseStr);
NSString *successResponse;
responseAlertView = [[UIAlertView alloc] init];
if ( [responseStr isEqualToString:#"SUCCESS"])
{
successResponse = #"Successfully connected! Click OK to starts screen sharing!";
responseAlertView.tag = 3;
[responseAlertView addButtonWithTitle:#"OK"];
[responseAlertView addButtonWithTitle:#"CANCEL"];
}
else
{
successResponse = #"There seems to be problem in connecting..Try connecting it again with proper Random Auth ID!";
responseAlertView.tag = 4;
[responseAlertView addButtonWithTitle:#"OK"];
}
responseAlertView.delegate = self;
[responseAlertView setTitle:#"Cobrowsing"];
[responseAlertView setMessage:successResponse];
[responseAlertView show];
}
break;
case NSStreamEventHasSpaceAvailable:
{
event = #"NSStreamEventHasSpaceAvailable";
NSLog(#"space : %d", [cobrowseSingletonIns.outputStream hasSpaceAvailable]);
if ( !cobrowseSingletonIns.bConnectionEstablished )
{
NSLog(#"NSStreamEventHasSpaceAvailable - Connection established, sharing is going to be established!");
if ( theStream == cobrowseSingletonIns.outputStream && !self.sentPing )
{
if ( [sessionID length]<=0 )
sessionID = #"EMPTY";
NSLog(#"sessionID : %#", sessionID);
NSData* data = [sessionID dataUsingEncoding:NSUTF8StringEncoding];
int num = [cobrowseSingletonIns.outputStream write:[data bytes] maxLength:([data length])];
if (-1 == num) {
NSLog(#"Error writing to stream %#: %#", cobrowseSingletonIns.outputStream, [cobrowseSingletonIns.outputStream streamError]);
}else{
NSLog(#"Wrote %i bytes to stream %#.", num, cobrowseSingletonIns.outputStream);
}
sentPing = YES;
}
}
else
{
NSLog(#"NSStreamEventHasSpaceAvailable - Connection already established");
if ( [cobrowseSingletonIns.outputStream hasSpaceAvailable] )
{
[self coShareScreen];
}
}
}
break;
case NSStreamEventErrorOccurred:
{
event = #"NSStreamEventErrorOccurred";
NSLog(#"NSStreamEventErrorOccurred - Can not connect to the host");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Co-browsing" message:#"Connection error, Cannot connect to the host!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
alertView.tag = 5;
[alertView show];
}
break;
case NSStreamEventEndEncountered:
event = #"NSStreamEventEndEncountered";
NSLog(#"NSStreamEventEndEncountered - Connection closed by the server");
break;
default:
event = #"** Unknown";
}
NSLog(#"%# : %#", io, event);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
int tag = alertView.tag;
NSLog(#"buttonIndex: %d ; alertView.tag: %d", buttonIndex, tag);
if ( alertView.tag==3 )
{
if ( buttonIndex==0 ) // for OK button
{
sentPing = NO;
cobrowseSingletonIns.bConnectionEstablished = YES;
[cobrowseSingletonIns shareScreen]; // call just once here, then 5 mins thread caller will be called in hasspaceavailable delegate method.
}
else if ( buttonIndex==1 ) // for Cancel button
{
NSLog(#"User selected Cancel, just stop the socket connection");
[cobrowseSingletonIns.outputStream close];
[cobrowseSingletonIns.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
}
else if (alertView.tag==4)
{
NSLog(#"Problem connecting with socket, just stop the socket connection");
sentPing = NO;
[cobrowseSingletonIns.outputStream close];
[cobrowseSingletonIns.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
else if (alertView.tag==5) // Socket connection closed Abruptly, one of the reasons, user manually locked of the phone. In this case, logout and love to login
{
NSLog(#"Socket connection closed Abruptly due to unknown reasons");
}
}
//-(void) shareScreen :(NSTimer *) timerInfo
-(void) coShareScreen
{
NSLog(#"coShareScreen called");
[cobrowseSingletonIns shareScreen];
}
#end
and
//
// CobrowseSingletonSocket.m
//
#import "CobrowseSingletonSocket.h"
#import "AppDelegate.h"
#import "MyUSAAViewController.h"
#import "USAASettingsViewController.h"
#import "ProductsViewController.h"
#import "InboxViewController.h"
#import "ContactUSViewController.h"
#import "VoiceViewController.h"
#import <QuartzCore/QuartzCore.h>
#implementation CobrowseSingletonSocket
static CobrowseSingletonSocket *sharedCobrowseSocketInstance = nil;
#synthesize loginViewController;
#synthesize outputStream;
#synthesize inputStream;
#synthesize bConnectionEstablished;
#synthesize socketIPAddress;
#synthesize servletIPAddress;
#synthesize servletPort;
+(CobrowseSingletonSocket *) sharedCobrowseSocketInstance
{
#synchronized ([CobrowseSingletonSocket class])
{
if ( !sharedCobrowseSocketInstance )
{
sharedCobrowseSocketInstance = [[super allocWithZone:NULL] init];
}
}
return sharedCobrowseSocketInstance;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedCobrowseSocketInstance];
}
-(void) takeScreenshotSend :(NSString *) endOrCancelString
{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
UIGraphicsBeginImageContext(appDelegate.window.bounds.size);
[appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSMutableData *data = [NSMutableData data];
data = (NSMutableData *) UIImagePNGRepresentation(image);
//[data writeToFile:#"screenshot.png" atomically:YES];
NSLog(#"shareScreen [data length] %i: ", [data length]);
NSData *newData = [endOrCancelString dataUsingEncoding:NSUTF16StringEncoding];
[data appendData:newData];
NSLog(#"shareScreen [data length] %i: ", [data length]);
//sentPing = YES;
int num = [self.outputStream write:[data bytes] maxLength:([data length])];
if (-1 == num) {
NSLog(#"Error writing to stream %#: %#", self.outputStream, [self.outputStream streamError]);
}else{
NSLog(#"Wrote %i bytes to stream %#.", num, self.outputStream);
//[self.outputStream close];
}
}
-(void) shareScreenAtInterval
{
NSLog(#"Screen sharing going to happen!");
[self takeScreenshotSend:#"END"]; // appending END, to detect the same on the server side and get out of reading data loop there.
}
-(void) shareScreen
{
NSLog(#"shareScreen called!");
[self performSelector:#selector(shareScreenAtInterval) withObject:nil afterDelay:5.0];
}
-(void) disconnectSocket
{
NSLog(#"Close the socket connection by user");
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(shareScreenAtInterval) object: nil];
//[NSObject cancelPreviousPerformRequestsWithTarget:self];
// Send Cancel message to socket
[self takeScreenshotSend:#"CANCEL"]; // appending CANCEL, to detect the same on the server side and get out of reading data loop there.
[self.outputStream close];
[self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.outputStream = nil;
self.bConnectionEstablished = NO;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Co-browsing" message:#"Screen sharing disconnected!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertView show];
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate.window.rootViewController dismissModalViewControllerAnimated:YES];
}
#end
Crash error in Xcode
Your problem is here -
[cobrowseSingletonIns.inputStream setDelegate:self];
[cobrowseSingletonIns.outputStream setDelegate:self]
Your HomeViewController sets itself as the delegate for the socket, but once it has been removed from view it will be deallocated, because the delegate property on the streams will be a weak reference.
You need to make sure the socket writing is completed and cleaned up when the view controller is removed. Try setting the delegates to nil in viewWillDisappear.
I am trying to monitor the callStates.I implemented an own class for this with this init method:
- (id) init
{
self = [super init];
if (!self) return nil;
callCenter = [[CTCallCenter alloc] init];
[callCenter setCallEventHandler: ^(CTCall* call) {
if ([call.callState isEqualToString: CTCallStateConnected]) {
} else if ([call.callState isEqualToString: CTCallStateDialing]) {
} else if ([call.callState isEqualToString: CTCallStateDisconnected]) {
} else if ([call.callState isEqualToString: CTCallStateIncoming]) {
}
NSLog(#"\n\n callEventHandler: %# \n\n", call.callState);
}];
return self;
}
#property(nonatomic, strong) CTCallCenter* callCenter;
I linked the CoreTelephony Framework in my Project...But the Block never gets called...If i put the same Code in my AppDelegate, it works...
Des it only work in AppDelegate?!
UPDATE:
I allocate my Class in my AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
VoiceReceiver *v __attribute__((unused)) = [[VoiceReceiver alloc] init];
....
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
VoiceReceiver *v __attribute__((unused)) = [[VoiceReceiver alloc] init];
....
}
Will not work. As soon as this callback is finished v will be dealloc'd.
If you need to use it in the appDelegate. Make the calss a property in the .h and init it where you are now.
e.g.
appDeletage.h
#property (nonatomic, strong) VoiceReceiver *voiceReciever;
appDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
voiceReciever = [[VoiceReceiver alloc] init];
....
}
The key difference here is that the appDeleagte is a singleton that will always be in memory so long as the app is running. Adding a strong property to this means it won't be removed unless the app crashes.
I have started exploring the Dropbox API for an app that I have where I would like the user to be able to back up the database file. The problem I have run into is that after the user links the app with their account (similar to logging in via Facebook) the app doesn't return to the foreground. When I manually go back to the app it is still on the backups screen, but the account has not been linked (as best as I can tell) and the handleOpenUrl app delegate method is not called.
Any ideas? or maybe someone knows a good tutorial for this. The sample Dropbox app works fine, and I'm doing my best to use it as a guide but obviously i've messed something up.
App Delegate:
#import "AppDelegate_iPad.h"
#import <DropboxSDK/DropboxSDK.h>
#interface AppDelegate_iPad () <DBSessionDelegate>
#end
#implementation AppDelegate_iPad
#synthesize window,viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.viewController = [[mainMenuViewController alloc]init];
[window addSubview:viewController.view]; //< this is a main menu viewcontroller for my app
[self.window makeKeyAndVisible];
// Set these variables before launching the app
NSString* appKey = #"XXXX";
NSString* appSecret = #"XXX";
NSString *root = kDBRootAppFolder;
NSString* errorMsg = nil;
if ([appKey rangeOfCharacterFromSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]].location != NSNotFound) {
errorMsg = #"Make sure you set the app key correctly in DBRouletteAppDelegate.m";
} else if ([appSecret rangeOfCharacterFromSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]].location != NSNotFound) {
errorMsg = #"Make sure you set the app secret correctly in DBRouletteAppDelegate.m";
} else if ([root length] == 0) {
errorMsg = #"Set your root to use either App Folder of full Dropbox";
} else {
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Info" ofType:#"plist"];
NSData *plistData = [NSData dataWithContentsOfFile:plistPath];
NSDictionary *loadedPlist =
[NSPropertyListSerialization
propertyListFromData:plistData mutabilityOption:0 format:NULL errorDescription:NULL];
NSString *scheme = [[[[loadedPlist objectForKey:#"CFBundleURLTypes"] objectAtIndex:0] objectForKey:#"CFBundleURLSchemes"] objectAtIndex:0];
if ([scheme isEqual:#"db-APP_KEY"]) {
errorMsg = #"Set your URL scheme correctly in DBRoulette-Info.plist";
}
}
DBSession* session =
[[DBSession alloc] initWithAppKey:appKey appSecret:appSecret root:root];
session.delegate = self; // DBSessionDelegate methods allow you to handle re-authenticating
[DBSession setSharedSession:session];
[session release];
if (errorMsg != nil) {
[[[[UIAlertView alloc]
initWithTitle:#"Error Configuring Session" message:errorMsg
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil]
autorelease]
show];
}
NSURL *launchURL = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
NSInteger majorVersion =
[[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:#"."] objectAtIndex:0] integerValue];
if (launchURL && majorVersion < 4) {
// Pre-iOS 4.0 won't call application:handleOpenURL; this code is only needed if you support
// iOS versions 3.2 or below
[self application:application handleOpenURL:launchURL];
return NO;
}
return YES;
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { /// this is never called
if ([[DBSession sharedSession] handleOpenURL:url]) {
if ([[DBSession sharedSession] isLinked]) {
NSLog(#"App linked successfully!");
// At this point you can start making API calls
}
return YES;
}
return NO;
}
#end
From the main Menu, the user pressed a backup button and that opens the following view controller:
#import "BackupManagerViewController.h"
#import <DropboxSDK/DropboxSDK.h>
#import <stdlib.h>
#interface BackupManagerViewController () <DBRestClientDelegate>
//#property (nonatomic, readonly) DBRestClient* restClient;
#end
#implementation BackupManagerViewController
#synthesize itemsArray,delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
//[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
return (orientation != UIDeviceOrientationLandscapeLeft) &&
(orientation != UIDeviceOrientationLandscapeRight);
}
- (IBAction)didPressLink {
if (![[DBSession sharedSession] isLinked]) {
[[DBSession sharedSession] link];
} else {
[[DBSession sharedSession] unlinkAll];
[[[[UIAlertView alloc]
initWithTitle:#"Account Unlinked!" message:#"Your dropbox account has been unlinked"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil]
autorelease]
show];
}
}
-(DBRestClient *)restClient{
if (restClient == nil) {
restClient = [[DBRestClient alloc]initWithSession:[DBSession sharedSession]];
restClient.delegate = self;
}
return restClient;
}
-(IBAction) closeButtonPressed {
[delegate closeBackupManager];
}
#end
Things to check are
Make sure you don't have two applications with same db-APP_KEY
Make sure only one of these is implemented (not both) in your application delegate.
(a)
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
(b)
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
Option (b) is deprecated so please go with the option (a) in your new applications
You have entered correct APP_KEY in the URL scheme .
I ran into the same problem, but got it working after deleting the sample app DBRoulette from the simulator. I also deleted my own app and restarted the simulator, but I am not sure if those steps were necessary.
Did you add the drop box URL schema to your app's info.plist?
I believe this problem had to do with running in the simulator. I ran it on a device and it worked fine.
I can reliably crash the simulator with this when releasing the GKSession after calling displayNameForPeer for another peer (not self), and I'm not sure if it's something I'm doing wrong or if it's a bug with Apple's Gamekit framework (and whether I need to worry about it, since I only see the crash under 4.0 and 4.1, not 4.2+).
The output is:
found available peer; checking name and ID... m4, 26176566
*** -[GKSessionInternal lock]: message sent to deallocated instance 0x7508900
Here's the minimal reproducible code set -- note that another GKSession must be visible on the network (so that there's an available peer found to call displayNameForPeer on) to trigger the crash. Running this same code on another device but without the makeUnavailable and killSession calls is adequate.
- (void)viewDidLoad
{
[self createSession];
[self makeAvailable];
peerListAvailable = [[NSMutableArray alloc] initWithArray:[currentSession peersWithConnectionState:GKPeerStateAvailable]];
for (NSString *peer in peerListAvailable)
{
// this method guarantees the crash on session release
NSLog(#"found available peer; checking name and ID... %#, %#",[currentSession displayNameForPeer:peer], peer);
}
[peerListAvailable release];
peerListAvailable = nil;
[self makeUnavailable];
[self killSession];
[super viewDidLoad];
}
- (void) createSession
{
if (!currentSession)
{
currentSession = [[GKSession alloc] initWithSessionID:#"GKTester" displayName:nil sessionMode:GKSessionModePeer];
currentSession.delegate = self;
currentSession.disconnectTimeout = 30;
[currentSession setDataReceiveHandler: self withContext:nil];
}
}
-(void) killSession
{
if (currentSession)
{
[currentSession disconnectFromAllPeers];
[currentSession setDelegate:nil];
[currentSession setDataReceiveHandler:nil withContext:nil];
[currentSession release]; // crash occurs after this
currentSession = nil;
}
}
-(void) makeAvailable
{
while (currentSession && !currentSession.available)
{
[currentSession setAvailable:YES];
[NSThread sleepForTimeInterval:.5];
}
}
-(void) makeUnavailable
{
while (currentSession && currentSession.available)
{
[NSThread sleepForTimeInterval:.5];
[currentSession setAvailable:NO];
}
}
You have an over-release in your code:
[currentSession disconnectFromAllPeers];
[currentSession setDelegate:nil];
[currentSession setDataReceiveHandler:nil withContext:nil];
[currentSession release]; // This is an over-release
currentSession = nil; // You are trying to access a variable after it's been released
You should release the currentSession member variable in dealloc only, like so:
- (void)dealloc
{
[currentSession release];
[super dealloc];
}