iOS: Crash after writing socket - ios

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.

Related

Multipeer Connection issue with ipv6 don't get an invitation

My App was rejected by Apple because it can't connect to other device running iOS 10.1.1 on Wi-Fi connected to an IPv6 network.
When I tap on connect, the app continues to search for invitees and no further user action is produced.
I use Multi-peer Connectivity and I never tested my App being connected to an IPv6(It's my first release). But the App run very fine without having any connection or being connected to IPv4 network.
I don't know why the App is running and connecting fine using the IPv4 and doesn't connect to peer if the iPad is connected to an IPv6 network.
So my Question: Is it possible to use Multi-peer Connectivity with IPv6 so that Apple can approve the App or how should I handle this Issue ?
Here is my Code, maybe it is something wrong there.
#interface ConnectionManageriOS7 () <MCSessionDelegate, MCBrowserViewControllerDelegate>
{
UILocalNotification *_expireNotification;
UIBackgroundTaskIdentifier _taskId;
}
#property (nonatomic, strong) MCSession *session;
#property (nonatomic, strong) MCPeerID *localPeerID;
#property (nonatomic, strong) MCBrowserViewController *browserVC;
#property (nonatomic, strong) MCAdvertiserAssistant *advertiser;
#end
static ConnectionManageriOS7 *_manager = nil;
#implementation ConnectionManageriOS7
+ (ConnectionManageriOS7 *)connectManager {
#synchronized([ConnectionManageriOS7 class]){
if (_manager == nil) {
_manager = [[ConnectionManageriOS7 alloc] init];
}
return _manager;
}
return nil;
}
- (id)init {
self = [super init];
if (self) {
[self setupSessionAndAdvertiser];
}
return self;
}
- (void)setupSessionAndAdvertiser {
_localPeerID = [[MCPeerID alloc] initWithDisplayName:[UIDevice currentDevice].name];;
_session = [[MCSession alloc] initWithPeer:_localPeerID];
_session.delegate = self;
}
- (void)connectWithDelegate:(id)delegate {
_delegate = delegate;
if (_session.connectedPeers.count) {
if ([_delegate respondsToSelector:#selector(didConntectedWithManager:)]) {
[_delegate didConntectedWithManager:self];
}
} else {
if (_advertiser == nil) {
_advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:VISUS_Service
discoveryInfo:nil
session:_session];
_isConnected = NO;
[_advertiser start];
}
if (_browserVC == nil) {
_browserVC = [[MCBrowserViewController alloc] initWithServiceType:VISUS_Service session:_session];
_browserVC.delegate = self;
}
[(UIViewController *)delegate presentViewController:_browserVC
animated:YES completion:nil];
}
}
- (void)sendMessage:(NSString *)message {
NSData *textData = [message dataUsingEncoding:NSASCIIStringEncoding];
NSLog(#"Send Data: %#", message);
NSError *error = nil;
[_session sendData:textData
toPeers:_session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
if (error) {
// 
[self session:_session peer:nil didChangeState:MCSessionStateNotConnected];
NSLog(#"error %#", error.userInfo);
}
}
- (void)stopService {
NSLog(#"Stop Service");
[_advertiser stop];
_advertiser = nil;
_browserVC = nil;
}
#pragma marks -
#pragma marks MCBrowserViewControllerDelegate
- (void) dismissBrowserVC{
[_browserVC dismissViewControllerAnimated:YES completion:nil];
}
// Notifies the delegate, when the user taps the done button
- (void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController {
if ([_delegate respondsToSelector:#selector(didConntectedWithManager:)]) {
[_delegate didConntectedWithManager:self];
}
[self dismissBrowserVC];
}
// Notifies delegate that the user taps the cancel button.
- (void)browserViewControllerWasCancelled:(MCBrowserViewController *)browserViewController{
if (_browserVC == nil) {
[browserViewController dismissViewControllerAnimated:YES completion:nil];
}else {
[self dismissBrowserVC];
}
}
#pragma marks -
#pragma marks MCBrowserViewControllerDelegate
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
if (state != MCSessionStateConnecting) {
if (state == MCSessionStateConnected) {
_isConnected = true;
if ([_delegate respondsToSelector:#selector(willConntectedWithManager:)]) {
[_delegate willConntectedWithManager:self];
}
}
else {
_isConnected = false;
[self stopService];
if ([_delegate respondsToSelector:#selector(didDisconntectedWithManager:)]) {
[_delegate didDisconntectedWithManager:self];
}
}
}
}
// Received data from remote peer
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
// Decode data back to NSString
NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Receive Data: %#", message);
// append message to text box:
dispatch_async(dispatch_get_main_queue(), ^{
if ([_delegate respondsToSelector:#selector(connectionManager:receivedString:)]) {
[_delegate connectionManager:self receivedString:message];
}
});
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error {
_isConnected = false;
[self stopService];
NSLog(#"----- Error ----- %#", error.localizedDescription);
}
// Received a byte stream from remote peer
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID {
}
// Start receiving a resource from remote peer
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress {
}
- (void) session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler
{
certificateHandler(YES);
}
- (void) createExpireNotification
{
[self killExpireNotification];
if (_session.connectedPeers.count != 0) // if peers connected, setup kill switch
{
NSTimeInterval gracePeriod = 20.0f;
// create notification that will get the user back into the app when the background process time is about to expire
NSTimeInterval msgTime = UIApplication.sharedApplication.backgroundTimeRemaining - gracePeriod;
UILocalNotification* n = [[UILocalNotification alloc] init];
_expireNotification = n;
_expireNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:msgTime];
_expireNotification.alertBody = #"Bluetooth Connectivity is about to disconnect. Open the app to resume Test";
_expireNotification.soundName = UILocalNotificationDefaultSoundName;
_expireNotification.applicationIconBadgeNumber = 1;
[UIApplication.sharedApplication scheduleLocalNotification:_expireNotification];
}
}
- (void) killExpireNotification
{
if (_expireNotification != nil)
{
[UIApplication.sharedApplication cancelLocalNotification:_expireNotification];
_expireNotification = nil;
}
}
- (void)bacgroundHandling {
_taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^
{
[self stopService];
[[UIApplication sharedApplication] endBackgroundTask:_taskId];
_taskId = UIBackgroundTaskInvalid;
}];
[self createExpireNotification];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
// http://down.vcnc.co.kr/WWDC_2013/Video/708.pdf -- wwdc tutorial, this part is towards the end (p119)
// self.arrayInvitationHandler = [NSArray arrayWithObject:[invitationHandler copy]];
// ask the user
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:peerID.displayName
message:#"Would like to create a session with you"
delegate:self
cancelButtonTitle:#"Decline" otherButtonTitles:#"Accept", nil];
[alertView show];
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// retrieve the invitationHandler and check whether the user accepted or declined the invitation...
BOOL accept = (buttonIndex != alertView.cancelButtonIndex) ? YES : NO;
// respond
if(accept) {
// void (^invitationHandler)(BOOL, MCSession *) = [self.arrayInvitationHandler objectAtIndex:0];
// invitationHandler(accept, self.mySession);
}
else
{
NSLog(#"Session disallowed");
}
}
- (void)terminate {
[self killExpireNotification];
[self stopService];
}
#end
I have solved the problem. For everybody with simular problem:
It wasn't a problem with IPv6, it is a matter of how to use Multipeer connectivity. In my Case I tryied to the the IPv6 connection with a iPad and a Simulator. And I used my Macbook for creating a nat64 network. And the reason why the simulator and iPad never saw each other the fact that they where not connected to same wifi network.
Solution:
Just take for testing two iPads and use your mac as nat64 network accesspoint.

Multipeer Connectivity kill session

I'm using a host/client approach to using MultiPeer Connectivity.
So, when a user his the disconnect button
-(IBAction)disconnect:(id)sender {
[_appDelegate.mcManager.session disconnect];
[_arrConnectedDevices removeAllObjects];
ConnectionsViewController *game = [self.storyboard instantiateViewControllerWithIdentifier:#"ConnectionsViewController"];
[self presentViewController:game animated:YES completion:nil];
}
Now, this works fine. From the hosts point of view it receives a disconnect message in the log. and the client moves to the new view controller. And the table is updated. with this.
-(void)peerDidChangeStateWithNotification:(NSNotification *)notification{
MCPeerID *peerID = [[notification userInfo] objectForKey:#"peerID"];
NSString *peerDisplayName = peerID.displayName;
MCSessionState state = [[[notification userInfo] objectForKey:#"state"] intValue];
if (state != MCSessionStateConnecting) {
if (state == MCSessionStateConnected) {
if (_makeSureImHost) {
[_arrConnectedDevices addObject:peerDisplayName];
[_tblConnectedDevices performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
else {
[self sendMessageToHostWithMessage:#"deviceInfo"];
}
}
else if (state == MCSessionStateNotConnected){
if ([_arrConnectedDevices count] > 0) {
int indexOfPeer = (int)[_arrConnectedDevices indexOfObject:peerDisplayName];
[_arrConnectedDevices removeObjectAtIndex:indexOfPeer];
NSLog(#"%# Disconnected", peerDisplayName);
[_tblConnectedDevices performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
_tblConnectedDevices.frame = CGRectMake(_backgroundImage.frame.size.width / 2 - 150, self.backgroundImage.frame.size.height / 3, 300, 150);
}
}
}
}
END OF LOBBY VIEW CONTROLLER
START OF CONNECTION VIEW CONTROLLER
When a client presses to browse for local devices this runs
- (IBAction)browseForDevices:(id)sender {
[UIView animateWithDuration:0.5f
animations:^{
_searchButton.frame = CGRectMake(-100, self.backgroundImage.frame.size.height/2 + 60, 100, 35.0);
_hostButton.alpha = 0;
_modeLabel.alpha = 0;
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[_appDelegate mcManager] setupPeerAndSessionWithDisplayName:[UIDevice currentDevice].name];
[[_appDelegate mcManager] advertiseSelf:false];
[[_appDelegate mcManager] setupMCBrowser];
[[[_appDelegate mcManager] browser] setDelegate:self];
_appDelegate.mcManager.browser.maximumNumberOfPeers = 1;
_appDelegate.mcManager.browser.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
[self presentViewController:[[_appDelegate mcManager] browser] animated:YES completion:nil];
});
}
When a connection is established
-(void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController {
[_appDelegate.mcManager.browser dismissViewControllerAnimated:NO completion:^{
[self launchViewController];
}];
}
-(void)launchViewController {
LobbyViewController *lobby = [self.storyboard instantiateViewControllerWithIdentifier:#"LobbyViewController"];
[self presentViewController:lobby animated:NO completion:nil];
}
From this
-(void)peerDidChangeStateWithNotification:(NSNotification *)notification {
MCPeerID *peerID = [[notification userInfo] objectForKey:#"peerID"];
NSString *peerDisplayName = peerID.displayName;
MCSessionState state = [[[notification userInfo] objectForKey:#"state"] intValue];
if (state != MCSessionStateConnecting) {
if (state == MCSessionStateConnected) {
[self browserViewControllerDidFinish:[[_appDelegate mcManager] browser]];
}
}
else if (state == MCSessionStateNotConnected){
if ([_arrConnectedDevices count] > 0) {
int indexOfPeer = (int)[_arrConnectedDevices indexOfObject:peerDisplayName];
[_arrConnectedDevices removeObjectAtIndex:indexOfPeer];
}
}
}
Now. When a connection is made for the first time. This all works flawlessly. It connects, loads the view, host starts the game, game works fine and data is transferred perfectly.
However, if you disconnect from the lobby. Get moved to the connection viewcontroller then browse for devices again. It will connect, however the lobby viewcontroller will NOT be in the view hierarchy and will close the browser and stay in the connection view controller.
Then, to top it off, the connection has been made. yet, when it receives a message from the host, it will send the response, twice.. or three times, or four, leading me to a dead end. The only thing I can presume is that the previous session is being remembered somehow from the "clients" point of view.
Now, steps I can take to avoid this mess. If I kill the app and relaunch it I can now connect again from the clients point of view. Which leads me to believe, the problem is on the clients end.
My problem is that I have to absolutely sort this out. So a disconnect will fully remove everything from the session. So they can reconnect again. And cannot rely on a message to tell the user to restart their application. It just cannot be.
Here's my entire MCManager.m file.
#implementation MCManager
-(id)init{
self = [super init];
if (self) {
_peerID = nil;
_session = nil;
_browser = nil;
_advertiser = nil;
}
return self;
}
-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName{
_peerID = [[MCPeerID alloc] initWithDisplayName:displayName];
_session = [[MCSession alloc] initWithPeer:_peerID];
_session.delegate = self;
}
-(void)setupMCBrowser{
_browser = [[MCBrowserViewController alloc] initWithServiceType:#"chat-files" session:_session];
}
-(void)advertiseSelf:(BOOL)shouldAdvertise{
if (shouldAdvertise) {
_advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:#"chat-files"
discoveryInfo:nil
session:_session];
[_advertiser start];
}
else{
[_advertiser stop];
_advertiser = nil;
}
}
-(void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
NSDictionary *dict = #{#"peerID": peerID,
#"state" : [NSNumber numberWithInt:state]
};
[[NSNotificationCenter defaultCenter] postNotificationName:#"MCDidChangeStateNotification"
object:nil
userInfo:dict];
}
-(void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
NSDictionary *dict = #{#"data": data,
#"peerID": peerID
};
[[NSNotificationCenter defaultCenter] postNotificationName:#"MCDidReceiveDataNotification"
object:nil
userInfo:dict];
}
-(void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress{
}
-(void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error{
}
-(void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID{
}
#end
#import <MultipeerConnectivity/MultipeerConnectivity.h>
#interface MCManager : NSObject <MCSessionDelegate>
#property (nonatomic, strong) MCPeerID *peerID;
#property (nonatomic, strong) MCSession *session;
#property (nonatomic, strong) MCBrowserViewController *browser;
#property (nonatomic, strong) MCAdvertiserAssistant *advertiser;
-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName;
-(void)setupMCBrowser;
-(void)advertiseSelf:(BOOL)shouldAdvertise;
#end
If anyone knows what I'm doing wrong I'd much appreciate it. This is driving me nuts.
[[NSNotificationCenter defaultCenter] removeObserver:name:object:];
Has fixed all my problems. Hopefully helps some other people too.
With Swift, I end the multipeer session as follows (after completing checking the deinit of session tracker):
func stopSession() {
self.serviceBrowser.stopBrowsingForPeers()
self.serviceBrowser.delegate = nil
self.serviceAdvertiser.stopAdvertisingPeer()
self.serviceAdvertiser.delegate = nil
self.session.disconnect()
self.peerSessionIDs.removeAll()
self.session.delegate = nil
self.session = nil
self.multipeerConnectivityService = nil
self.serviceType = nil
}
In other words, everything that was registered and the initializer is de-initialized. I am doing this in reverse order, but I'm not sure if order is important here.

Get this UIAlert working

I am recieving an error on this line in my ViewControllerLogin.m file or anywhere a UIAlert shows up...
[UIAlertView error:#"Enter username and password over 4 chars each."];
The above code gives me an error in the issues editor: "no known class for method selector". I identified the method 'error' in another class in Xcode. Does anyone know why I am getting this error?
UPDATE ViewControllerLogin.m (the UIViewAlets are at the bottom)
#import "ViewControllerLogin.h"
#import "UIAlertView+error.h"
#import "API.h"
#include <CommonCrypto/CommonDigest.h>
#define kSalt #"adlfu3489tyh2jnkLIUGI&%EV(&0982cbgrykxjnk8855"
#implementation ViewControllerLogin
- (void)viewWillAppear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:NO animated:animated];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:NO animated:animated];
[super viewWillDisappear:animated];
}
-(void)viewDidLoad {
[super viewDidLoad];
//focus on the username field / show keyboard
[fldUsername becomeFirstResponder];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"qwertygreen.png"] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.titleTextAttributes = #{NSForegroundColorAttributeName: [UIColor whiteColor]};
self.title = #"play";
//changes the buttn color
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
// Do any additional setup after loading the view.
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - View lifecycle
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(IBAction)btnLoginRegisterTapped:(UIButton*)sender {
//form fields validation
if (fldUsername.text.length < 4 || fldPassword.text.length < 4)
{
[UIAlertView error:#"Enter username and password over 4 chars each."];
return;
}
//salt the password
NSString* saltedPassword = [NSString stringWithFormat:#"%#%#", fldPassword.text, kSalt];
//prepare the hashed storage
NSString* hashedPassword = nil;
unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];
//hash the pass
NSData *data = [saltedPassword dataUsingEncoding: NSUTF8StringEncoding];
if (CC_SHA1([data bytes], [data length], hashedPasswordData)) {
hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
} else {
[UIAlertView error:#"Password can't be sent"];
return;
}
//check whether it's a login or register
NSString* command = (sender.tag==1)?#"register":#"login";
NSMutableDictionary* params =[NSMutableDictionary dictionaryWithObjectsAndKeys:command, #"command", fldUsername.text, #"username", hashedPassword, #"password", nil];
//make the call to the web API
[[API sharedInstance] commandWithParams:params onCompletion:^(NSDictionary *json) {
//result returned
NSDictionary* res = [[json objectForKey:#"result"] objectAtIndex:0];
if ([json objectForKey:#"error"]==nil && [[res objectForKey:#"IdUser"] intValue]>0) {
[[API sharedInstance] setUser: res];
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
//show message to the user
[[[UIAlertView alloc] initWithTitle:#"Logged in" message:[NSString stringWithFormat:#"Welcome %#",[res objectForKey:#"username"]] delegate:nil cancelButtonTitle:#"Close" otherButtonTitles: nil] show];
} else {
//error
[UIAlertView error:[json objectForKey:#"error"]];
}
}];
}
#end
You need to import UIKit.
#import <UIKit/UIKit.h>

Clean array by using delegate

I made an AR app that recognize image and show the object recognized in an AlertView. In the AlertView I have 2 buttons: Add and Cancel, I'm using the UIAlertViewDelegate to understand which button the user pressed. If the user press the Add button, the object recognized will be stored in an array. I pass this array to another ViewController, in which I set up a TableView. On the bottom of this TableView there's a button "Pay" to go to another ViewController in which I display the total price of the object recognized. From the last ViewController I can press a button to pay the objects I selected by using the AR. Now when I press this button the app close this ViewController and go back to the first ViewController, but the array in which I stored the object that the AR recognized it's full. To delete the content of this array I thought that the best way is to use the delegation methods, so I made this:
PaymentViewController.h
#import <UIKit/UIKit.h>
#protocol PaymentViewControllerDelegate;
#interface PaymentViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *labelTotal;
- (IBAction)buttonClosePaymentVC:(id)sender;
- (IBAction)buttonPay:(id)sender;
#property(nonatomic,strong)NSString *total;
#property(assign) id<PaymentViewControllerDelegate> delegate;
#end
#protocol PaymentViewControllerDelegate <NSObject>
- (void)cleanReportArray;
#end
PaymentViewController.m
#import "PaymentViewController.h"
#interface PaymentViewController () <UIAlertViewDelegate>
#end
#implementation PaymentViewController
#synthesize delegate = _delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.labelTotal.text = self.total;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonClosePaymentVC:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonPay:(id)sender {
NSString *pay = [NSString stringWithFormat:#"Stai per pagare %#, procedi?", self.total];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:pay delegate:self cancelButtonTitle:#"Si" otherButtonTitles:#"No", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
// Procedura per il pagamento e cancellazione del file plist
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"objects.plist"];
NSError *error;
if (![[NSFileManager defaultManager]removeItemAtPath:path error:&error]) {
NSLog(#"Errore: %#", error);
}
__weak UIViewController *vcThatPresentedCurrent = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
[vcThatPresentedCurrent dismissViewControllerAnimated:YES completion:nil];
}];
[self.delegate cleanReportArray];
}
if (buttonIndex == 1) {
// Non deve far nulla: fa scomparire l'UIAlertView
}
}
Here I post to you the method of the class that will use the delegate:
Interface of the ScannerViewController.m
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
In ViewDidLoad I inserted this rows:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
And in the ScannerViewController.m I implemented the method I declared in PaymentViewController.h:
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
I tested my app on my iPhone, the app works fine until I try to pay the objects I scanned by camera, indeed, I tried to pay the object, but it doesn't clean the array in which I stored the objects scanned.
What's wrong in my code? I used an tutorial on the web to understand better how the delegation method works. I hope you can help me to fix this issue, thank you
UPDATE:
here i will post my ScannerViewController code:
ScannerViewController.h
#import <UIKit/UIKit.h>
#interface ScannerViewController : UIViewController
#end
ScannerViewController.m
#import "ScannerViewController.h"
#import "PaymentViewController.h"
#import "ReportViewController.h"
#import "MSScannerSession.h"
#import "MSResult.h"
#import "XmlReader.h"
static int kMSScanOptions = MS_RESULT_TYPE_IMAGE |
MS_RESULT_TYPE_EAN8 |
MS_RESULT_TYPE_EAN13;
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
#implementation ScannerViewController {
MSScannerSession *_scannerSession;
NSString *nameOfObjectScanned;
XmlReader *reader;
NSMutableArray *arrayObjectAdded;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_scannerSession = [[MSScannerSession alloc] initWithScanner:[MSScanner sharedInstance]];
[_scannerSession setScanOptions:kMSScanOptions];
[_scannerSession setDelegate:self];
}
return self;
}
- (void)session:(MSScannerSession *)scanner didScan:(MSResult *)result {
if (!result) {
return;
}
[_scannerSession pause];
NSString *resultStr = nil;
if (result) {
switch ([result getType]) {
case MS_RESULT_TYPE_IMAGE:
resultStr = [NSString stringWithFormat:#"Immagine trovata: %#", [result getValue]];
break;
case MS_RESULT_TYPE_EAN8:
case MS_RESULT_TYPE_EAN13:
resultStr = [NSString stringWithFormat:#"EAN trovato: %#", [result getValue]];
break;
default:
break;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
UIActionSheet *asView = [[UIActionSheet alloc]initWithTitle:resultStr delegate:self cancelButtonTitle:#"OK" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
asView.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[asView showInView:self.view];
[self addObjectToList:resultStr];
});
}
- (void)addObjectToList:(NSString *)objectName {
// Ricerca dell'oggetto
NSString *object = [objectName substringFromIndex:18];
if ([object isEqualToString:#"Binario_con_coppia"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_colorati"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_rossi"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Bici_da_corsa"]) {
[self showAlert:object];
}
}
- (void)showAlert:(NSString*)name {
name = [name stringByReplacingOccurrencesOfString:#"_" withString:#" "];
nameOfObjectScanned = name;
NSString *message = [NSString stringWithFormat:#"Ho riconosciuto questo oggetto: %#, vuoi aggiungerlo al carrello?", name];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:message delegate:self cancelButtonTitle:#"Aggiungi" otherButtonTitles:#"Annulla", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"Aggiungi");
for (int i = 0; i < [reader.objArray count]; i++) {
if ([[reader.objArray[i]objectForKey:#"name"] isEqualToString:nameOfObjectScanned]) {
// Salvo il nome dell'oggetto trovato, il prezzo e la descrizione
NSString *name = [reader.objArray[i]objectForKey:#"name"];
NSString *desc = [reader.objArray[i]objectForKey:#"desc"];
NSString *price = [reader.objArray[i]objectForKey:#"price"];
NSDictionary *newObjectAdded = [[NSDictionary alloc]init];
newObjectAdded = #{#"name": name,
#"desc": desc,
#"price": price};
[arrayObjectAdded addObject:newObjectAdded];
}
}
} else {
NSLog(#"Annulla");
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
[_scannerSession resume];
}
- (void)viewDidLoad
{
[super viewDidLoad];
arrayObjectAdded = [[NSMutableArray alloc]init];
CALayer *videoPreviewLayer = [self.videoPreview layer];
[videoPreviewLayer setMasksToBounds:YES];
CALayer *captureLayer = [_scannerSession previewLayer];
[captureLayer setFrame:[self.videoPreview bounds]];
[videoPreviewLayer insertSublayer:captureLayer below:[[videoPreviewLayer sublayers] objectAtIndex:0]];
reader = [[XmlReader alloc]init];
[reader parseXml];
[_scannerSession startCapture];
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
}
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
- (void)dealloc {
[_scannerSession stopCapture];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)stopScanner:(id)sender {
ReportViewController *reportVC = [[ReportViewController alloc]initWithNibName:#"ReportViewController" bundle:nil];
reportVC.reportArray = arrayObjectAdded;
[reportVC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:reportVC animated:YES completion:nil];
}
#end
To recognize picture I'm using this AR SDK. I hope you can help me to understand where's my issue
Your problem is that in viewDidLoad you have the code:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
this is the last thing you do in that method. So the instance of PaymentViewController that you create and set the delegate on is immediately destroyed (by ARC).
You need to modify your code so that you call setDelegate: on the actual instance of PaymentViewController that is presented on screen as this is the instance that needs to use the delegate (it receives the callback from the alert view).

How to add a textfield to an NSMutableArray

I'm trying to present what was entered into a textfield into a nsmutable array that will later be displayed.
I think that the problem is in the -(void)viewDidLoad method but I included all of the code just in case. The catch is that I will be leaving this page and then returning to it after another piece of information is selected. As this happens, I need to keep track of EACH thing that was entered into the textfield. Thanks for any help!
#import "EnteringCoursesViewController.h"
#import "SelectRotationController.h"
#implementation EnteringCoursesViewController
#synthesize classField;
#synthesize indicatedClass;
#synthesize labelClassTitle;
#synthesize selectRotationController;
#synthesize classesEnteredTable;
- (IBAction)chooseType {
UIActionSheet *typeSheet = [[UIActionSheet alloc]
initWithTitle:#"Class types"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:#"Core Class", #"Elective", nil];
[typeSheet showInView:self.view];
[typeSheet release];
}
- (void)actionSheet:(UIActionSheet *)typeSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
self.indicatedClass = classField.text;
NSString *indicatedString = indicatedClass;
NSString *greeting = [[NSString alloc]
initWithFormat:#"%# meets 6 times per rotation", indicatedString];
labelClassTitle.text = greeting;
labelClassTitle.hidden = NO;
[greeting release];
[indicatedClass release];
}
else if (buttonIndex == 1) {
self.indicatedClass = classField.text;
NSString *indicatedString = indicatedClass;
NSString *greeting = [[NSString alloc]
initWithFormat:#"%# meets 3 times per rotation", indicatedString];
labelClassTitle.text = greeting;
labelClassTitle.hidden = NO;
[greeting release];
[indicatedClass release];
}
}
- (IBAction)chooseFirstMeeting:(id)sender {
SelectRotationController *selectView = [[SelectRotationController alloc]
initWithNibName:#"SelectRotationController"
bundle:[NSBundle mainBundle]];
[selectView.navigationItem setTitle:#"First Period Day Choose"];
[self.navigationController pushViewController:self.selectRotationController animated:YES];
self.selectRotationController = selectView;
[selectView release];
}
- (IBAction)enteredClassText:(id)sender {
NSMutableArray *classesEntered = [[NSMutableArray alloc] init];
[classesEntered addObject:indicatedClass];
[classesEntered release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidLoad {
self.navigationItem.hidesBackButton = YES;
[super viewDidLoad];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[classField release];
[labelClassTitle release];
[indicatedClass release];
[selectRotationController release];
[classesEnteredTable release];
[super dealloc];
}
#end
If viewDidLoad is called "indicatedClass" is not yet initialised and therefore nil.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html
Important Raises an NSInvalidArgumentException if anObject is nil.
If you want to save that by leaving the view, add the addObject-Call in the viewDidUnload-method. Definitely you should check if the value is nil ;)
I dont see any alloc for your variable indicatedClass but an release!? It might be that the variable doesnt exists if viewDidUnload is calling.
EDIT
You init an NSMutableArray, add the object to this array and after that you released that object. Therefore the Data is away. You must save your array therewith you can use the content later. Keyword: NSUserDefaults ;)
Check also of nil values:
- (IBAction)enteredClassText:(id)sender {
if (indicatedClass != nil) {
NSMutableArray *classesEntered = [[NSMutableArray alloc] init];
[classesEntered addObject:indicatedClass];
[classesEntered release];
}
}
If the sender is an UILabel you can also use this snippet:
- (IBAction)enteredClassText:(id)sender {
if (sender.text != nil) {
NSMutableArray *classesEntered = [NSMutableArray arrayWithObject:sender.text];
// TODO: Save your array to NSUserDefaults...
}
}

Resources