I realize what the error log is telling me. There is a spot where apple is shutting down my app. It's taking too long to start up, or become active, or shut down. I can't seem to figure out where this is happening though. What do I need to move off this thread and/or out of these methods?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self preload];
[NSThread sleepForTimeInterval:1.5];
[window addSubview:[viewController view]];
[NSNotificationCenter postNavigationNotificationForName:whatever];
[window makeKeyAndVisible];
return YES;
}
-(void)preload
{
[[[UIWebView alloc] init] release];
if (interface == iPad)
{
UIViewController *dummy = [[[UIViewController alloc] init] autorelease];
[[[UIPopoverController alloc] initWithContentViewController:dummy] release];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(preloadComplete:)
name:UIWindowDidBecomeVisibleNotification
object:nil];
UITextField *field = [[[UITextField alloc] init] autorelease];
[window addSubview:field];
[field becomeFirstResponder];
[field resignFirstResponder];
[field removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIWindowDidBecomeVisibleNotification
object:nil];
}
- (void)applicationWillTerminate:(UIApplication *)application
{
NSError *err = nil;
[[context sharedInstance] cleanup];
[[[[context sharedInstance] user] managedObjectContext] save:&err];
}
- (void)applicationWillResignActive:(UIApplication *)application
{
NSError *err = nil;
[[[[context sharedInstance] user] managedObjectContext] save:&err];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
context *ctx = [context sharedInstance];
if (ctx) {
[ctx makeSureYouCanReachThis];
}
if ([[ctx user] userState] != userStateUnknownUser) {
NSTimeInterval ti = time;
if (fabs([[ctx dateLaunched] timeIntervalSinceNow]) > ti)
{
[ctx setDateLaunched:[NSDate date]];
[[ctx user] becomeFault];
[[ctx user] delayedBackgroundAuth];
[ctx authenticateUser:[[ctx user] defaultUsername]
withPassword:[[ctx user] defaultPassword]];
}
else
{
{
if (fabs([[ctx lastBecameActive] timeIntervalSinceNow]) >= time)
{
[ctx setLastBecameActive:[NSDate date]];
[ctx synchServerCompleted];
}
}
else
{
[ctx setLastBecameActive:[NSDate date]];
}
}
}
}
Related
After searching on Stackoverflow, I was unable to find a duplicate question with the solution I needed and at one point this code was working fine until recently, here is the stack trace from the debug console:
2016-10-10 17:01:27.873567 Eboticon[1628:411719] [DYMTLInitPlatform] platform initialization successful
2016-10-10 17:01:28.042711 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.ratchpack3
2016-10-10 17:01:28.042838 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.greetingspack1
2016-10-10 17:01:28.042902 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.baepack1
2016-10-10 17:01:28.042959 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.ratchpack1
2016-10-10 17:01:28.043014 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.churchpack1
2016-10-10 17:01:28.043068 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.greekpack2
2016-10-10 17:01:28.043122 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.ratchpack2
2016-10-10 17:01:28.043176 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.churchpack2
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
2016-10-10 17:06:16.186456 Eboticon[1628:411555] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x18f5b41c0 0x18dfec55c 0x18f493ad4 0x1000ec6d8 0x1000eb7ec 0x19546e61c 0x19567ed60 0x195684ad0 0x195699270 0x195681ab4 0x191155904 0x191155770 0x191155b18 0x18f562278 0x18f561bc0 0x18f55f7c0 0x18f48e048 0x1954677cc 0x195462550 0x100118f9c 0x18e4705b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
When adding an Exception breakpoint, it points to this line of code being the problem:
[arrImagePagerImages addObject:[UIImage imageWithData:data]];
Here is the full code base with the problematic code towards the end:
#import "AppDelegate.h"
#import "JMCategoriesData.h"
#import "MasterViewController.h"
#import "GAI.h"
#import "GAIFields.h"
#import "iRate.h"
#import "DDLog.h"
#import "DDTTYLogger.h"
#import "Harpy.h"
#import "Constants.h"
#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>
#import <Parse/Parse.h>
#import "SWRevealViewController.h"
#import "RightViewController.h"
#import "XOSplashVideoController.h"
#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
#interface AppDelegate()<SWRevealViewControllerDelegate>
#end
#implementation AppDelegate
#pragma mark -
#pragma mark AppDelegate Methods
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Register for Push Notitications
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge |
UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes
categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
//[self showSplashVideo];
//PARSE
//[Parse setApplicationId:#"gBcNi8fexXd1Uiggm6e2hRFuOPkoEefsbxLDNzO7"
//clientKey:#"dKZXWc9CXdksCA7HPVSCp0Yz0tTBQuqnQEvXKwL6"];
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
[self initialize];
// Override point for customization after application launch.
return YES;
}
/**
* Setup iRate rating scheme
*/
- (void) configureiRate
{
#try {
[iRate sharedInstance].appStoreID = appStoreID;
[iRate sharedInstance].daysUntilPrompt = 10;
[iRate sharedInstance].usesUntilPrompt = 5;
//[iRate sharedInstance].verboseLogging = YES;
[iRate sharedInstance].promptAtLaunch = YES;
[iRate sharedInstance].eventsUntilPrompt = 5;
[iRate sharedInstance].promptForNewVersionIfUserRated = YES;
[iRate sharedInstance].remindPeriod = 7;
//TODO: Set below to no before deploying!
[iRate sharedInstance].previewMode = NO;
DDLogInfo(#"%#: Number of events until iRate launch %lu", NSStringFromClass(self.class), (unsigned long)[iRate sharedInstance].eventCount);
DDLogInfo(#"%#: Number of iRate uses %lu", NSStringFromClass(self.class), (unsigned long)[iRate sharedInstance].usesCount);
DDLogInfo(#"%#: Prompt for rating criteria met: %lu", NSStringFromClass(self.class), (unsigned long)[iRate sharedInstance].shouldPromptForRating);
}
#catch (NSException *exception) {
DDLogError(#"[ERROR] in enabling iRate: %#", exception.description);
}
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
currentInstallation.channels = #[ #"global" ];
[currentInstallation saveInBackground];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PFPush handlePush:userInfo];
}
- (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 throttle down OpenGL ES frame rates. 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 inactive 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:.
}
#pragma mark -
#pragma mark Initialize
- (void) showSplashVideo {
CGRect frame = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:frame];
NSLog(#"Screen Height %f", self.window.frame.size.height);
NSString *portraitVideoName = #"EboticonIntroNEW640x960";
NSString *portraitImageName = #"iphone640x960.png";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && self.window.frame.size.height > 480) {
portraitImageName = #"iphone640x1136.png";
portraitVideoName = #"EboticonIntroNEW640x1136";
}
NSString *landscapeVideoName = nil; // n/a
NSString *landscapeImageName = nil; // n/a
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
portraitVideoName = #"EboticonIntroNEW768x1024";
portraitImageName = #"ipad768x1024.png";
landscapeVideoName = #"EboticonIntroNEW768x1024.mp4";
landscapeImageName = #"ipad768x1024.png";
}
// our video
NSURL *portraitUrl = [[NSBundle mainBundle] URLForResource:portraitVideoName withExtension:#"mp4"];
NSURL *landscapeUrl = [[NSBundle mainBundle] URLForResource:landscapeVideoName withExtension:#"mp4"];
// our splash controller
XOSplashVideoController *splashVideoController =
[[XOSplashVideoController alloc] initWithVideoPortraitUrl:portraitUrl
portraitImageName:portraitImageName
landscapeUrl:landscapeUrl
landscapeImageName:landscapeImageName
delegate:self];
// we'll start out with the spash view controller in the window
self.window.rootViewController = splashVideoController;
[self.window makeKeyAndVisible];
}
- (void) initialize {
_products = nil;
[[EboticonIAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) {
if (success) {
_products = products;
NSLog(#"--------DONE-------");
}
}];
arrImagePagerImages = [[NSMutableArray alloc]init];
for (NSInteger i = 1 ; i <= 4 ; i ++){
NSString *sUrl = [NSString stringWithFormat:#"http://www.inclingconsulting.com/eboticon/store/banner%i.png", (int)i];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: sUrl]];
if (data == nil)continue;
[arrImagePagerImages addObject:[UIImage imageWithData:data]];
}
//Setting up Navigation Bar
[[UINavigationBar appearance] setBarTintColor:UIColorFromRGB(0x380063)];
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8];
shadow.shadowOffset = CGSizeMake(0, 1);
[[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:245.0/255.0 green:245.0/255.0 blue:245.0/255.0 alpha:1.0], NSForegroundColorAttributeName,
shadow, NSShadowAttributeName,
[UIFont fontWithName:#"Avenir-Black" size:21.0], NSFontAttributeName, nil]];
[[UINavigationBar appearance] setTintColor:UIColorFromRGB(0xFf6c00)]; //Color of back button
//Tabbar With sidebar Items
NSNumber *caption = #(1); //initialize caption to on
self.tabBarController = [[TabViewController alloc] initWithCaption:caption];
RightViewController *rightViewController = [[RightViewController alloc] init];
SWRevealViewController *mainRevealController = [[SWRevealViewController alloc]
initWithRearViewController:rightViewController frontViewController:self.tabBarController];
mainRevealController.rightViewController = rightViewController;
mainRevealController.delegate = self;
self.viewController = mainRevealController;
//Add Tab Bar
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//self.window.rootViewController = self.tabBarController;
self.window.rootViewController = self.viewController;
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default.png"]];
[self.window addSubview:splashScreen];
[self.window makeKeyAndVisible];
[UIView animateWithDuration:0.3 animations:^{splashScreen.alpha = 0.0;}
completion:(void (^)(BOOL)) ^{
[splashScreen removeFromSuperview];
}
];
// Present Window before calling Harpy
//[self.window makeKeyAndVisible];
//GOOGLE ANALYTICS INITIALIZER
// Optional: automatically send uncaught exceptions to Google Analytics.
[GAI sharedInstance].trackUncaughtExceptions = YES;
// Optional: set Google Analytics dispatch interval to e.g. 20 seconds.
[GAI sharedInstance].dispatchInterval = 20;
// Optional: set Logger to VERBOSE for debug information.
[[[GAI sharedInstance] logger] setLogLevel:kGAILogLevelError];
// Initialize tracker. Replace with your tracking ID.
#ifdef FREE
[[GAI sharedInstance] trackerWithTrackingId:#"UA-48552713-3"];
DDLogInfo(#"Google Analytics Enabled for Lite Version");
#else
[[GAI sharedInstance] trackerWithTrackingId:#"UA-48552713-4"];
DDLogInfo(#"Google Analytics Enabled for Paid Version");
#endif
//Set dry run to yes for testing purposes
[[GAI sharedInstance] setDryRun:NO];
//Set version for app tracking
NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
[[GAI sharedInstance].defaultTracker set:kGAIAppVersion value:version];
[[GAI sharedInstance].defaultTracker set:kGAISampleRate value:#"50.0"];
//Cocoalumberjack init files
[DDLog addLogger:[DDTTYLogger sharedInstance]];
[[DDTTYLogger sharedInstance] setColorsEnabled:YES];
//configure iRate
[self configureiRate];
//Harpy
//TODO: turn on Harpy
[self configureHarpy];
//FABRIC
[Fabric with:#[CrashlyticsKit]];
}
/**
* Setup Harpy update reminder
*/
- (void) configureHarpy
{
#try {
// Set the App ID for your app
#ifdef FREE
[[Harpy sharedInstance] setAppID:#"977505283"];
#else
[[Harpy sharedInstance] setAppID:#"899011953"];
#endif
// Set the UIViewController that will present an instance of UIAlertController
[[Harpy sharedInstance] setPresentingViewController:_window.rootViewController];
// (Optional) The tintColor for the alertController
//[[Harpy sharedInstance] setAlertControllerTintColor:#"<#alert_controller_tint_color#>"];
// (Optional) Set the App Name for your app
#ifdef FREE
[[Harpy sharedInstance] setAppName:#"Eboticon Lite"];
#else
[[Harpy sharedInstance] setAppName:#"Eboticon"];
#endif
// Perform check for new version of your app
[[Harpy sharedInstance] checkVersion];
}
#catch (NSException *exception) {
DDLogError(#"[ERROR] in enabling Harpy: %#", exception.description);
}
}
#pragma mark -
#pragma mark Reveal Controller Delegate
- (NSString*)stringFromFrontViewPosition:(FrontViewPosition)position
{
NSString *str = nil;
if ( position == FrontViewPositionLeft ) str = #"FrontViewPositionLeft";
if ( position == FrontViewPositionRight ) str = #"FrontViewPositionRight";
if ( position == FrontViewPositionRightMost ) str = #"FrontViewPositionRightMost";
if ( position == FrontViewPositionRightMostRemoved ) str = #"FrontViewPositionRightMostRemoved";
return str;
}
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position
{
NSLog( #"%#: %#", NSStringFromSelector(_cmd), [self stringFromFrontViewPosition:position]);
}
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position
{
NSLog( #"%#: %#", NSStringFromSelector(_cmd), [self stringFromFrontViewPosition:position]);
}
- (void)revealController:(SWRevealViewController *)revealController willRevealRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didRevealRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController willHideRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didHideRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController willShowFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didShowFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController willHideFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didHideFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
#pragma mark Splash Video
- (void)splashVideoLoaded:(XOSplashVideoController *)splashVideo
{
// load up our real view controller, but don't put it in to the window until the video is done
// if there's anything expensive to do it should happen in the background now
//
// self.viewController = [[XOViewController alloc] initWithNibName:#"XOViewController" bundle:nil];
}
- (void)splashVideoComplete:(XOSplashVideoController *)splashVideo
{
// swap out the splash controller for our app's
//self.window.rootViewController = self.viewController;
[self initialize];
}
#end
When we comment out the problematic line, the app runs fine but won't display the needed array. When I do an NSLog of the array, it displays the addresses of objects. Any suggestions on why it won't display the objects and the system thinks its nil?
[UIImage imageWithData:] may return nil if the data supplied cannot be converted to an image. If this happens then you will get the exception because you are adding the result to an array without checking, and NSMutableArray cannot contain nil.
You should convert the image separately and only add it to the array if it is non-nil:
UIImage *image = [UIImage imageWithData:data];
if (image != nil) {
[arrImagePagerImages addObject:image];
} else {
NSLog(#"Unable to convert data to image");
}
acctually the problem is with your nsdata assignment
for (NSInteger i = 1 ; i <= 4 ; i ++){
NSString *sUrl = [NSString stringWithFormat:#"http://www.inclingconsulting.com/eboticon/store/banner%i.png", (int)i];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: sUrl]];
if (data == nil)continue;
[arrImagePagerImages addObject:[UIImage imageWithData:data]];
}
as you are initiating new nsdata with url so it could be nil so for achieving this you have to check the length as well also you have to check check that data should not be null.
please try this
for (NSInteger i = 1 ; i <= 4 ; i ++){
NSString *sUrl = [NSString stringWithFormat:#"http://www.inclingconsulting.com/eboticon/store/banner%i.png", (int)i];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: sUrl]];
if ([data isKindOfClass:[NSData class]] && data.length == 0){
NSLog(#"no data");
}else{
[arrImagePagerImages addObject:[UIImage imageWithData:data]]}
}
I have this piece of code for playing audio, but once it is finished, I want to play the same audio again and again, I think I should use numberofloops=-1, but where I need to use this directly. Please help me.
#import "JetNapMusicPlayer.h"
#import <AVFoundation/AVFoundation.h>
#interface JetNapMusicPlayer()
#property(nonatomic,strong) AVQueuePlayer *avQueuePlayer;
#end
static JetNapMusicPlayer *sharedManager = nil;
#implementation JetNapMusicPlaye
#pragma mark Singleton Methods
+ (id)sharedManager {
#synchronized(self) {
if(sharedManager == nil)
sharedManager = [[super alloc] init];
}
return sharedManager;
}
- (id)init {
if (self = [super init]) {
// [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];
MPRemoteCommand *playCommand = rcc.playCommand;
[playCommand setEnabled:YES];
[playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent *event) {
[(JetNapMusicPlayer *)[JetNapMusicPlayer sharedManager] play];
return MPRemoteCommandHandlerStatusSuccess;
}];
MPRemoteCommand *pauseCommand = rcc.pauseCommand;
[pauseCommand setEnabled:YES];
[pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent *event) {
[(JetNapMusicPlayer *)[JetNapMusicPlayer sharedManager] pause];
return MPRemoteCommandHandlerStatusSuccess;
}];
}
return self;
}
- (void)dealloc {
[super dealloc];
}
-(AVPlayer *)avQueuePlayer
{
if (!_avQueuePlayer) {
[self initSession];
_avQueuePlayer = [[AVQueuePlayer alloc] init];
}
return _avQueuePlayer;
}
-(void)initSession
{
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(audioSessionInterrupted:)
name: AVAudioSessionInterruptionNotification
object: [AVAudioSession sharedInstance]];
//set audio category with options - for this demo we'll do playback only
NSError *categoryError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&categoryError];
if (categoryError) {
NSLog(#"Error setting category! %#", [categoryError description]);
}
//activation of audio session
NSError *activationError = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
if (!success) {
if (activationError) {
NSLog(#"Could not activate audio session. %#", [activationError localizedDescription]);
} else {
NSLog(#"audio session could not be activated!");
}
}
}
#pragma mark - notifications
-(void)audioSessionInterrupted:(NSNotification*)interruptionNotification
{
NSLog(#"interruption received: %#", interruptionNotification);
}
#pragma mark - player actions
-(void) pause
{
[[self avQueuePlayer] pause];
}
-(void) play
{
[[self avQueuePlayer] play];
}
-(void) clear
{
[[self avQueuePlayer] removeAllItems];
}
#pragma mark - remote control events
#pragma mark - Kony FFI
+ (BOOL)playMusic:(NSString *)filename artistname:(NSString *)artistname songname:(NSString *)songname {
NSString *name = [filename stringByDeletingPathExtension];
NSString *ext = [filename pathExtension];
AVPlayerItem *avSongItem = [[AVPlayerItem alloc] initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[[NSString alloc] initWithFormat:name] ofType:ext]]];
if (avSongItem) {
[(JetNapMusicPlayer *)[JetNapMusicPlayer sharedManager] clear];
[[[JetNapMusicPlayer sharedManager] avQueuePlayer] insertItem:avSongItem afterItem:nil];
[(JetNapMusicPlayer *)[JetNapMusicPlayer sharedManager] play];
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = #{MPMediaItemPropertyTitle: songname, MPMediaItemPropertyArtist:artistname};
}
return YES;
}
+ (BOOL)stopMusic {
[(JetNapMusicPlayer *)[JetNapMusicPlayer sharedManager] pause];
[(JetNapMusicPlayer *)[JetNapMusicPlayer sharedManager] clear];
return YES;
}
#end
To loop a song use below code after alloc init of avSongItem.
avSongItem.actionAtItemEnd = AVPlayerActionAtItemEndNone;
More info : Looping a video with AVFoundation AVPlayer?
Also as mentioned in the link use notification.
avSongItem.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[avPlayer currentItem]];
this will prevent the player to pause at the end.
in the notification:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[p seekToTime:kCMTimeZero];
}
I currently have a progress view which shows the current amount of how much of a file has been downloaded so far. When the user clicks the download button the progress succesfully updates and when they leave the view controller and return to it while it is still downloading the progress still updates successfuly. However my problem is when the download finishes and the user has left and returned to the view the progress view no longer responds to any updates. I have did some research into multi-threading and seen that many people suggest to do any UI updates in the main thread like so:
[self performSelectorOnMainThread:#selector(progressUpdate) withObject:nil waitUntilDone:NO];
So I tried it in my code and the still got the same results (once the user leaves and returns to the view controller after the download has finished the progress view does not respond to any updates). I then added a NSLog to see if the method was being called and the debugger outputted the NSLog. So what is going on? Here is the code for the view controller:
VideoTest.m
#import "VideoTest.h"
#import "AppDelegate.h"
#import "FileDownloadInfo.h"
#interface VideoTest ()
#property (nonatomic, strong) NSURLSession *session;
#property (nonatomic, strong) NSMutableArray *arrFileDownloadData;
#property (nonatomic, strong) NSURL *docDirectoryURL;
-(void)initializeFileDownloadDataArray;
-(int)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier;
#end
#implementation VideoTest{
NSString *url;
}
#synthesize moviePlayer;
#synthesize download;
#synthesize videoAlreadyPlaying, progressView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Setting video URl
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
url = #"http://therosary.info/AppVideos/TheChaplet/Information%20on%20Divine%20Mercy.mp4";
//selectors set
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(MPMoviePlayerPlaybackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enteredFullscreen:) name:MPMoviePlayerDidEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
//Play the movie
videoAlreadyPlaying=#"TRUE";
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:url]];
[self.view addSubview:moviePlayer.view];
self.moviePlayer.view.frame = CGRectMake(0,64,320,220);
[moviePlayer play];
[self initializeFileDownloadDataArray];
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
self.docDirectoryURL = [URLs objectAtIndex:0];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:#"com.jjdoherty98.Marion_s_Net"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
if([appDelegate.isAlreadyDownloading isEqual:#"FALSE"] || appDelegate.isAlreadyDownloading==nil){
self.progressView.hidden = YES;
progressView.progress=0;
}
if([appDelegate.isAlreadyDownloading isEqual:#"TRUE"]){
[self performSelectorOnMainThread:#selector(progressUpdate) withObject:nil waitUntilDone:NO];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.isMovingFromParentViewController || self.isBeingDismissed) {
NSLog(#"Left View");
[moviePlayer stop];
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown;
}
- (BOOL)shouldAutorotate{
AppDelegate *mainDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
mainDelegate.fullScreenVideoIsPlaying = #"TRUE";
return YES;
}
- (void)MPMoviePlayerPlaybackStateDidChange:(NSNotification *)notification
{
if (moviePlayer.playbackState == MPMoviePlaybackStatePlaying)
{ //playing
videoAlreadyPlaying = #"TRUE";
}
if (moviePlayer.playbackState == MPMoviePlaybackStateStopped)
{ //stopped
}if (moviePlayer.playbackState == MPMoviePlaybackStatePaused)
{ //paused
}if (moviePlayer.playbackState == MPMoviePlaybackStateInterrupted)
{ //interrupted
}if (moviePlayer.playbackState == MPMoviePlaybackStateSeekingForward)
{ //seeking forward
}if (moviePlayer.playbackState == MPMoviePlaybackStateSeekingBackward)
{ //seeking backward
}
}
- (void)willEnterFullscreen:(NSNotification*)notification {
NSLog(#"willEnterFullscreen");
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = #"TRUE";
}
- (void)enteredFullscreen:(NSNotification*)notification {
NSLog(#"enteredFullscreen");
}
- (void)willExitFullscreen:(NSNotification*)notification {
NSLog(#"willExitFullscreen");
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = #"FALSE";
}
- (void)exitedFullscreen:(NSNotification*)notification {
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSLog(#"exitedFullscreen");
if(appDelegate.CurrentProgress==0){
progressView.hidden=TRUE;
}else{
[self performSelectorOnMainThread:#selector(progressUpdate) withObject:nil waitUntilDone:NO];
}
}
- (void)playbackFinished:(NSNotification*)notification {
NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(#"playbackFinished. Reason: Playback Ended");
videoAlreadyPlaying=#"FALSE";
[moviePlayer stop];
[moviePlayer play];
break;
case MPMovieFinishReasonPlaybackError:
NSLog(#"playbackFinished. Reason: Playback Error");
videoAlreadyPlaying=#"FALSE";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Video Failed To Load!"
message:#"Unable to connect to server, please try again later!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
break;
case MPMovieFinishReasonUserExited:
NSLog(#"playbackFinished. Reason: User Exited");
videoAlreadyPlaying=#"FALSE";
break;
default:
break;
}
[self.moviePlayer setFullscreen:NO animated:YES];
}
-(IBAction)buttonPressed:(id)sender{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if([appDelegate.isThereInternet isEqual:#"TRUE"]){
if([appDelegate.isAlreadyDownloading isEqual: #"FALSE"]){
//If there is internet and not already downloading
progressView.hidden=FALSE;
progressView.progress=0;
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:0];
fdi.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:fdi.downloadSource]];
fdi.taskIdentifier = fdi.downloadTask.taskIdentifier;
// Start the task.
[fdi.downloadTask resume];
}}
if ([appDelegate.isThereInternet isEqual:#"FALSE"]) {
//No internet available
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Unable to connect to server"
message:#"Internet connection appears to be offline, please try again later!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
if([appDelegate.isAlreadyDownloading isEqual:#"TRUE"]){
//Is already downloaing
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"File Already Downloading"
message:#"Multiple files can not be downloaded at the same time!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
-(void)initializeFileDownloadDataArray{
self.arrFileDownloadData = [[NSMutableArray alloc] init];
[self.arrFileDownloadData addObject:[[FileDownloadInfo alloc] initWithFileTitle:nil andDownloadSource:url]];
}
-(int)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier{
int index = 0;
for (int i=0; i<[self.arrFileDownloadData count]; i++) {
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:i];
if (fdi.taskIdentifier == taskIdentifier) {
index = i;
break;
}
}
return index;
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *destinationFilename = downloadTask.originalRequest.URL.lastPathComponent;
NSURL *destinationURL = [self.docDirectoryURL URLByAppendingPathComponent:destinationFilename];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if ([fileManager fileExistsAtPath:[destinationURL path]]) {
[fileManager removeItemAtURL:destinationURL error:nil];
}
BOOL success = [fileManager copyItemAtURL:location
toURL:destinationURL
error:&error];
if (success) {
int index = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:index];
fdi.isDownloading = NO;
fdi.downloadComplete = YES;
// Set the initial value to the taskIdentifier property of the fdi object,
// so when the start button gets tapped again to start over the file download.
fdi.taskIdentifier = -1;
// In case there is any resume data stored in the fdi object, just make it nil.
fdi.taskResumeData = nil;
}
else{
NSLog(#"Unable to copy temp file. Error: %#", [error localizedDescription]);
}
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if (error != nil) {
NSLog(#"Download completed with error: %#", [error localizedDescription]);
appDelegate.isAlreadyDownloading=#"FALSE";
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Failed to download!"
message:#"Unable to connect to the server!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
});
}
else{
appDelegate.isAlreadyDownloading=#"FALSE";
NSLog(#"Download finished successfully.");
dispatch_async(dispatch_get_main_queue(), ^{
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:0];
fdi.isDownloading = NO;
fdi.downloadComplete = YES;
fdi.taskIdentifier = -1;
fdi.taskResumeData = nil;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Download Complete!"
message:#"Go to downloads section to view the file now!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
});
}
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
NSLog(#"Unknown transfer size");
}
else{
int index = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:index];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.isAlreadyDownloading=#"TRUE";
fdi.downloadProgress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
appDelegate.CurrentProgress = fdi.downloadProgress;
[self performSelectorOnMainThread:#selector(progressUpdate) withObject:nil waitUntilDone:NO];
}
}
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([downloadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
// Make nil the backgroundTransferCompletionHandler.
appDelegate.backgroundTransferCompletionHandler = nil;
progressView.hidden=TRUE;
// Show a local notification when all downloads are over.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"All files have been downloaded!";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}
}
}];
}
-(void)progressUpdate{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if ([appDelegate.isAlreadyDownloading isEqual:#"TRUE"]) {
progressView.progress = appDelegate.CurrentProgress;
[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:#selector(progressUpdate) userInfo:nil repeats:NO];
NSLog(#"Is this method being called");
if (appDelegate.CurrentProgress==1) {
progressView.hidden=TRUE;
}
}
}
#end
Any help would be appreciated!
I am trying to establish one to one peer connection using multipeer connectivity framework. When i am sending invitation to nearby peer that device gets connected(sometime takes long time to get connected), and the peer which has send the request is always taking long time to change its state to connected & once it is connected immediately it is disconnecting from the session. I tried to debug the issue but not found anything, dont know what wrong is happening, please let me know if i am missing anything or any mistake is done in code.
Below given is the code snippet of the same.
MPCHandler.m
#define DidChangeStateNotification #"E_DidChangeStateNotification"
#define DidReceiveDataNotification #"E_DidReceiveDataNotification"
#define DidInviteNotification #"E_DidInvitedNotification"
#define DidReceivedInvetationNotification #"E_DidReceivedInvetationNotification"
static NSString * const EServiceType = #"E-service";
#interface MPCHandler ()
#property AppDelegate *appDelegate;
#end
#implementation MPCHandler
- (void)setupPeerWithDisplayName:(NSString *)displayName {
self.appDelegate = [[UIApplication sharedApplication] delegate];
self.peerID = [[MCPeerID alloc] initWithDisplayName:displayName];
self.connectedPeers = [NSMutableArray array];
self.foundPeers = [NSMutableArray array];
self.invitedPeers = [NSMutableArray array];
}
- (void)setupSession {
self.session = [[MCSession alloc] initWithPeer:self.peerID securityIdentity:nil encryptionPreference:MCEncryptionNone];
self.session.delegate = self;
}
- (void)setupBrowser {
self.browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID serviceType:EServiceType];
self.browser.delegate = self;
}
- (void)advertiseSelf:(BOOL)advertise {
if (advertise) {
self.advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID discoveryInfo:nil serviceType:EServiceType];
self.advertiser.delegate = self;
[self.advertiser startAdvertisingPeer];
} else {
[self.advertiser stopAdvertisingPeer];
self.advertiser = nil;
}
}
#pragma MCSessionDelegate methods
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
NSDictionary *userInfo = #{ #"peerID": peerID,
#"state" : #(state) };
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:DidChangeStateNotification
object:nil
userInfo:userInfo];
});
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
NSDictionary *userInfo = #{ #"data": data,
#"peerID": peerID };
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:DidReceiveDataNotification
object:nil
userInfo:userInfo];
});
}
- (void)session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL))certificateHandler{
certificateHandler(YES);
}
#pragma MCNearbyServiceAdvertiserDelegate methods
// Incoming invitation request. Call the invitationHandler block with YES and a valid session to connect the inviting peer to the session.
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler{
NSDictionary *info =[NSDictionary dictionaryWithObject:peerID.displayName forKey:#"displayName"];
NSLog(#"%# Received Invetation from : %#",self.peerID.displayName,peerID.displayName);
invitationHandler(YES,self.session);
[self.connectedPeers addObject:peerID];
self.invited = NO;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:DidReceivedInvetationNotification
object:nil
userInfo:info];
});
}
#pragma MCNearbyServiceBrowserDelegate methods
// Found a nearby advertising peer
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo: (NSDictionary *)info{
// NSLog(#"Peer : %# found.",peerID.displayName);
// if (![self.peerID isEqual:peerID]) {
NSLog(#"%# Found Peer : %#",self.peerID.displayName,peerID.displayName);
[self.foundPeers addObject:peerID];
if (![self.connectedPeers containsObject:peerID])
{
if ([self.invitedPeers count] == 0 && [self.session.connectedPeers count]==0)
{
NSLog(#"%# Invited Peer : %#",self.peerID.displayName,peerID.displayName);
[self.invitedPeers addObject:peerID];
[browser invitePeer:peerID
toSession:self.session
withContext:[#"Empath" dataUsingEncoding:NSUTF8StringEncoding]
timeout:0];
// [browser stopBrowsingForPeers];
self.invited = YES;
NSDictionary *userInfo = #{ #"peerID": peerID };
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:DidInviteNotification
object:nil
userInfo:userInfo];
});
}
}
// }
}
// A nearby peer has stopped advertising
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID{
[self.foundPeers removeObject:peerID];
[self.invitedPeers removeAllObjects];
[browser startBrowsingForPeers];
}
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error
{
NSLog( #"Unable to start browsing for peers. Error: %#", error );
}
ViewController.m
#define DidChangeStateNotification #"E_DidChangeStateNotification"
#define DidReceiveDataNotification #"E_DidReceiveDataNotification"
#define DidInviteNotification #"E_DidInvitedNotification"
#define DidReceivedInvetationNotification #"E_DidReceivedInvetationNotification"
#interface ViewController ()
#property (nonatomic, strong) AppDelegate *appDelegate;
#end
#implementation ViewController
#synthesize txtMessage;
#synthesize tvHistory;
#synthesize btnSend;
#synthesize lblName;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
// self.appDelegate.connectedPeers = [NSMutableArray array];
// self.appDelegate.foundPeers = [NSMutableArray array];
[self AddObservers];
[self setUserInteraction:NO];
[self.lblName setText:#""];
[self.btnSend setUserInteractionEnabled:NO];
[self performSelector:#selector(advertisePeer) withObject:nil afterDelay:0.0];
}
-(void) AddObservers{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleReceivedDataWithNotification:)
name:DidReceiveDataNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(peerChangedStateWithNotification:)
name:DidChangeStateNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedInvetationWithNotification:)
name:DidReceivedInvetationNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(peerInvitedWithNotification:)
name:DidInviteNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(sessionDidTimeout:) name:kSessionDidTimeoutNotification object:nil];
}
-(void) advertisePeer{
[self setUserInteraction:NO];
[self.lblName setText:#""];
[self.appDelegate.mpcHandler setupPeerWithDisplayName:[UIDevice currentDevice].name];
[self.appDelegate.mpcHandler setupSession];
[self.appDelegate.mpcHandler advertiseSelf:YES];
[self.btnSend setUserInteractionEnabled:YES];
}
- (IBAction)searchAndConnectPeer:(id)sender{
[self.lblName setText:#"Searching..."];
if (self.appDelegate.mpcHandler.session != nil) {
[[self.appDelegate mpcHandler] setupBrowser];
[[[self.appDelegate mpcHandler] browser] startBrowsingForPeers];
}
}
- (IBAction)sendMessage:(id)sender{
NSString *messageToSend = [txtMessage text];
NSUInteger len = 0;
if ([messageToSend length]) {
NSData *messageAsData = [messageToSend dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
[self.appDelegate.mpcHandler.session sendData:messageAsData
toPeers:self.appDelegate.mpcHandler.session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
// If any error occurs, just log it.
// Otherwise set the following couple of flags to YES, indicating that the current player is the creator
// of the game and a game is in progress.
len = [[tvHistory text] length];
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
[self.tvHistory setText:[NSString stringWithFormat:#"%#",[error localizedDescription]]];
} else{
NSString *history = [NSString stringWithFormat:#"Me : %#\n\n",messageToSend];
[self.tvHistory setText:[self.tvHistory.text stringByAppendingString:history]];
}
}
[self.txtMessage setText:#""];
[self.tvHistory scrollRangeToVisible:NSMakeRange([self.tvHistory.text length], len)];
}
- (void)peerInvitedWithNotification:(NSNotification *)notification{
[self setUserInteraction:NO];
MCPeerID *peerID = [[notification userInfo] objectForKey:#"peerID"];
[self.lblName setText:[NSString stringWithFormat:#"Connecting to %#...",peerID.displayName]];
}
- (void)receivedInvetationWithNotification:(NSNotification *)notification{
[self setUserInteraction:YES];
NSString *name = [[notification userInfo] objectForKey:#"displayName"];
[self.lblName setText:[NSString stringWithFormat:#"Connected : %#",name]];
}
- (void)peerChangedStateWithNotification:(NSNotification *)notification {
// Get the state of the peer.
int state = [[[notification userInfo] objectForKey:#"state"] intValue];
MCPeerID *peerID = [[notification userInfo] objectForKey:#"peerID"];
// We care only for the Connected and the Not Connected states.
// The Connecting state will be simply ignored.
if (state == MCSessionStateConnected) {
// We'll just display all the connected peers (players) to the text view.
NSString *allPlayers = #"Connected : ";
allPlayers = [allPlayers stringByAppendingString:[NSString tringWithFormat:#"%#",peerID.displayName]];
[self.lblName setText:allPlayers];
[self setUserInteraction:YES];
NSLog(#"%#...",allPlayers);
// // Fire up the timer upon first event
// if(!_idleTimer) {
// [self resetIdleTimer];
// }
}else if (state == MCSessionStateConnecting){
[self setUserInteraction:NO];
[self.lblName setText:[NSString stringWithFormat:#"Connecting to %#...",peerID.displayName]];
NSLog(#"Connecting %#...",peerID.displayName);
}else if (state == MCSessionStateNotConnected){
NSLog(#"Disconnected %#...",peerID.displayName);
// [self sessionDidTimeout:nil];
}
}
-(void) setUserInteraction:(BOOL)enabled{
[self.btnSend setUserInteractionEnabled:enabled];
[self.txtMessage setUserInteractionEnabled:enabled];
}
- (void)handleReceivedDataWithNotification:(NSNotification *)notification {
// Get the user info dictionary that was received along with the notification.
NSDictionary *userInfoDict = [notification userInfo];
// Convert the received data into a NSString object.
NSData *receivedData = [userInfoDict objectForKey:#"data"];
NSString *message = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
// Keep the sender's peerID and get its display name.
MCPeerID *senderPeerID = [userInfoDict objectForKey:#"peerID"];
NSString *senderDisplayName = senderPeerID.displayName;
// Add this guess to the history text view.
NSUInteger len = [[tvHistory text] length];
NSString *history = [NSString stringWithFormat:#"%# : %#\n\n", senderDisplayName, message];
[self.tvHistory setText:[self.tvHistory.text stringByAppendingString:history]];
[self.tvHistory scrollRangeToVisible:NSMakeRange([self.tvHistory.text length], len)];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
- (void)resetIdleTimer
{
if (_idleTimer) {
[_idleTimer invalidate];
}
// Schedule a timer to fire in kApplicationTimeoutInMinutes * 60
int timeout = kSessionTimeoutInSeconds;
_idleTimer = [NSTimer scheduledTimerWithTimeInterval:timeout
target:self
selector:#selector(idleTimerExceeded)
userInfo:nil
repeats:NO];
}
- (void)idleTimerExceeded {
/* Post a notification so anyone who subscribes to it can be notified when
* the application times out */
[[NSNotificationCenter defaultCenter]
postNotificationName:kSessionDidTimeoutNotification object:nil];
}
- (void) sessionDidTimeout:(NSNotification *) notif {
// [self setUserInteraction:NO];
//
// [self.lblName setText:#"Session expired..."];
//
// NSLog(#"============================Session Expired...=====================");
//
// [[[self.appDelegate mpcHandler] session] disconnect];
//
// if ([[[self appDelegate]mpcHandler] invited]) {
// [self performSelector:#selector(advertisePeer) withObject:nil afterDelay:0.0];
// [self performSelector:#selector(searchAndConnectPeer:) withObject:nil afterDelay:1.0];
// }
}
Check for BTM disconnection to service message in the logs .It is a problem with Apple Bluetooth which they have acknowledged.Try without Bluetooth i.e peer-peer wifi or infrastructure networks
I am following a tutorial doing a Game Center Turn-based match, tic-tac-toe game, and my view controller is not loaded. It works when i use the source code but not with the code i have typed myself, from the book. I have checked and cant find any difference.
I do get into Game Center and when i click on "Play your turn" it loads the initial screen with the button "Begin game" and not, as the original code, the "tictactoeGameViewController" as it suppose to.
I would very much appreciate if someone could help me out here :-)
Here is my code:
#import "ViewController.h"
#import "tictactoeGameViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)beginGame:(id)sender {
GKMatchRequest *match = [[GKMatchRequest alloc]init];
[match setMaxPlayers:2];
[match setMinPlayers:2];
GKTurnBasedMatchmakerViewController *tmvc = nil;
tmvc = [[GKTurnBasedMatchmakerViewController alloc]initWithMatchRequest:match];
[tmvc setTurnBasedMatchmakerDelegate:self];
[self presentModalViewController:tmvc animated:YES];
[tmvc release];
[match release];
}
- (void)viewDidLoad {
[super viewDidLoad];
if ([GameCenterManager isGameCenterAvailable]) {
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(localUserAuthenticationChanged:) name:GKPlayerAuthenticationDidChangeNotificationName object:nil];
gcManager = [[GameCenterManager alloc]init];
[gcManager setDelegate:self];
[gcManager authenticateLocalUser];
}
}
-(void)processGameCenterAuthentication:(NSError *)error {
if (error != nil) {
NSLog(#"An error occured during authentication: %#", [error localizedDescription]);
}
}
-(void)localUserAuthenticationChanged:(NSNotification *)notif {
NSLog(#"Authentication Changed: %#", notif.object);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - GCTurnBasedMatchHelperDelegate
-(void)turnBasedMatchmakerViewController:(GKTurnBasedMatchmakerViewController *)viewController didFindMatch:(GKTurnBasedMatch *)match {
[self dismissModalViewControllerAnimated:YES];
tictactoeGameViewController *gameVC = [[tictactoeGameViewController alloc]init];
gameVC.match = match;
[[self navigationController]pushViewController:gameVC animated:YES];
[gameVC release];
}
-(void)turnBasedMatchmakerViewController:(GKTurnBasedMatchmakerViewController *)viewController playerQuitForMatch:(GKTurnBasedMatch *)match {
[match participantQuitOutOfTurnWithOutcome:GKTurnBasedMatchOutcomeQuit withCompletionHandler:^(NSError *error) {
if (error) {
NSLog(#"An error occured ending match: %#", [error localizedDescription]);
}
}];
}
-(void)turnBasedMatchmakerViewController:(GKTurnBasedMatchmakerViewController *)viewController didFailWithError:(NSError *)error {
NSLog(#"Turned Based Matchmaker Failed with Error: %#", [error localizedDescription]);
}
-(void)turnBasedMatchmakerViewControllerWasCancelled:(GKTurnBasedMatchmakerViewController *)viewController {
[self dismissModalViewControllerAnimated:YES];
}
#end
I did find the solution:
The ViewController must be RootViewController so i changed:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
To:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *controller = [[ViewController alloc] init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}