This is my first question here. I'm trying to make an app that will work with Core Audio. I found this framework http://theamazingaudioengine.com/ that I'm trying to use and so far I managed to do the first thing in the documentation, which is to play a file. However, by custom initializing the UIViewController in app's delegate, I lose all its content and the view controller comes black with no other elements.
My UIViewController only has one button, which I wanted to use to start the playback of the file, but since I have no access to it, at the moment, the file starts playing when the project builds.
Any idea what am I doing wrong?
This is my appDelegate:
#implementation SoundCheckAppDelegate
#synthesize window = _window;
#synthesize audioController = _audioController;
#synthesize viewController = _viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create an instance of the audio controller, set it up and start it running
self.audioController = [[[AEAudioController alloc] initWithAudioDescription:[AEAudioController nonInterleaved16BitStereoAudioDescription] inputEnabled:YES] autorelease];
_audioController.preferredBufferDuration = 0.005;
[_audioController start:NULL];
// Create and display view controller
self.viewController = [[SoundCheckViewController alloc] initWithAudioController:_audioController];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
#end
And my UIViewController:
#interface SoundCheckViewController ()
#property (nonatomic, strong) AEAudioController *audioController;
#property (nonatomic, strong) AEAudioFilePlayer *loop;
#end
#implementation SoundCheckViewController
- (id)initWithAudioController:(AEAudioController*)audioController {
self.audioController = audioController;
NSError *error;
NSURL *file = [[NSBundle mainBundle] URLForResource:#"Southern Rock Drums" withExtension:#"m4a"];
self.loop = [AEAudioFilePlayer audioFilePlayerWithURL:file
audioController:_audioController
error:&error];
if(error)
NSLog(#"couldn't start loop");
_loop.removeUponFinish = YES;
_loop.loop = YES;
_loop.completionBlock = ^{
self.loop = nil;
};
[_audioController addChannels:[NSArray arrayWithObject:_loop]];
return self;
}
#end
Since you're using a storyboard, you should take all that code out of the app delegate. The storyboard automatically instantiates your initial controller and puts it on screen. By alloc init'ing one, you're just creating another one that doesn't have any custom view.
To add your audio controller, you should add code in the viewDidLoad method of SoundCheckViewController that does that, rather than in an init method. This would be the usual way to do this, but I'm not sure what is possible with the framework you're using.
I think you should initialize your view controller first.
- (id)initWithAudioController:(AEAudioController*)audioController {
// THIS LINE IS MISSING IN YOUR CODE
self = [super initWithNibName:#"SoundCheckViewController" bundle:nil];
if ( self ) {
self.audioController = audioController;
...
}
return self;
}
Related
STILL NO SOLUTION - REDUCED TEST CASE PROJECT HERE:
http://www.friendlycode.co.uk/assets/Bugfix.zip
I'm new to Xcode/Objective C and have done a lot of research but cannot find an answer. There are loads of similar questions here but none of them have helped me solve this.
Files:
app.h
app.m
Settings.h
Settings.m
I have some background music playing which starts when the app is launched via ViewDidLoad in the ViewController.m file.
I am trying to stop this from the Settings.m file if the Music switch is touched and set to off.
Please see code below (have removed unnecessary outlets/methods etc)
The NSLog outputs 'attempting to stop audio' but audio is not stopped. I think I have referenced the ViewController class correctly so unsure why it won't stop?
app.h
#import <UIKit/UIKit.h>
#import <Social/Social.h>
#import "AVFoundation/AVAudioPlayer.h"
#interface ViewController : GAITrackedViewController <AVAudioPlayerDelegate, UIActionSheetDelegate>
{
// removed
}
#property (nonatomic, retain) AVAudioPlayer *BackgroundMusicPlayer;
#end
app.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Play Background music
[self PlayBackgroundMusic];
}
-(void)PlayBackgroundMusic
{
NSString* resourcePath = [[NSBundle mainBundle]
pathForResource:#"music-file"
ofType:#"aiff"];
NSLog(#"Path to play: %#", resourcePath);
NSError* err;
//Initialize our player pointing to the path to our resource
_BackgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath] error:&err];
if( err ){
//bail!
NSLog(#"Failed with reason: %#", [err localizedDescription]);
}
else{
//set our delegate and begin playback
_BackgroundMusicPlayer.delegate = self;
[_BackgroundMusicPlayer play];
_BackgroundMusicPlayer.numberOfLoops = -1;
_BackgroundMusicPlayer.currentTime = 0;
_BackgroundMusicPlayer.volume = 0.5;
}
}
Settings.h
#import <UIKit/UIKit.h>
#import "app.h"
#interface Settings : GAITrackedViewController <AVAudioPlayerDelegate, UIActionSheetDelegate>
{
IBOutlet UIButton *BackButton;
IBOutlet UISwitch *MusicSwitch;
IBOutlet UISwitch *SoundFXSwitch;
// Get instance of ViewController object
ViewController *home;
}
-(IBAction)BackButton:(id)sender;
-(IBAction)ToggleMusic:(id)sender;
-(IBAction)ToggleSoundFX:(id)sender;
#end
Settings.m
#import "Settings.h"
#interface Settings ()
#end
#implementation Settings
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)ToggleMusic:(id)sender {
// Get instance of ViewController object
//home = [[ViewController alloc] init];
if (MusicSwitch.on)
{
[home.BackgroundMusicPlayer play];
}
else {
[home.BackgroundMusicPlayer stop];
NSLog(#"Attempting to stop audio");
}
}
-(IBAction)ToggleSoundFX:(id)sender {
if (SoundFXSwitch.on)
{
}
else{
}
}
-(IBAction)BackButton:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
I think the problem is with the ViewController *home.
Your AvAudioPlayer object is in the app.h in the interface ViewController.
But in your code , you are not initialising the ViewController object "home"
in settings.m. So effectively , you are trying to access and stop a player that
is not created.
To access the AVAudioPlayer object add the following code in your viewDidload of settings.h.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//initialise the audioPlayer object.
home=[[ViewController alloc] init];
}
In your Settings.h , declare the ViewController property as assign
#interface Settings : GAITrackedViewController <UIActionSheetDelegate>
{
#property (nonatomic, assign) ViewController *home;
}
-(IBAction)ToggleMusic:(id)sender {
if (MusicSwitch.on)
{
[self.home.BackgroundMusicPlayer play];
}
else {
[self.home.BackgroundMusicPlayer stop];
}
}
From your app.m , assign the home property as self _BackgroundMusicPlayer.home = self;
-(void)PlayBackgroundMusic
{
NSString* resourcePath = [[NSBundle mainBundle]
pathForResource:#"music-file"
ofType:#"aiff"];
NSLog(#"Path to play: %#", resourcePath);
NSError* err;
//Initialize our player pointing to the path to our resource
_BackgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath] error:&err];
if( err ){
//bail!
NSLog(#"Failed with reason: %#", [err localizedDescription]);
}
else{
//set our delegate and begin playback
_BackgroundMusicPlayer.delegate = self;
settingsViewObj.home = self; //recommended after the 'Settings' view allocation code.
[_BackgroundMusicPlayer play];
_BackgroundMusicPlayer.numberOfLoops = -1;
_BackgroundMusicPlayer.currentTime = 0;
_BackgroundMusicPlayer.volume = 0.5;
}
}
Notes:
Read more about object communication
Read more about Objective C coding standards
Read more about class hierarchy
If I am understanding your code correctly, it seems you are creating a instance of your initial view controller and trying to stop the music player property of that instance. If that is the case, the music player you are trying to stop is already stopped, because it is a a separate instance of AVAudioPlayer that was created when you created an instance of your ViewController. In order to stop the music player from the first view controller, you could try this:
In the Settings.h file, add an AVAudioPlayer property just like in app.h
#property (strong, nonatomic) AVAudioPlayer *backgroundMusic;
Then when segueing to the settings view controller, pass the audio player to the new controller using prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"YourSegueName"]) {
if([segue.destinationViewController isKindOfClass:[YourSettingsClass class]]) {
YourSettingsClass *destination = segue.destinationViewController;
destination.backgroundMusic = self.BackgroundMusicPlayer;
}
}
}
You should now be able to simply call [self.backgroundMusic stop] and stop your tunes.
Ensure that you #import your Settings controller class in your app class to access it in the prepareForSegue method.
You can't access the instance of an object of another class created by it, by importing
it.Here You have to access the same object instance , in order to stop the AVAudioPlayer.
So you have to place the object somewhere unique, like AppDelegate.
Try declaring the AVAudioPlayer in the appdelegate.h.
In Appdeleagte.h
#property (nonatomic, strong) AVAudioPlayer *BackgroundMusicPlayer;
and in your app.h you can access the player as follows.
AppDelegate *appDelegate;
//in your viewDidLoad
appDelegate=[[UIApplication sharedApplication]delegate];
//in your PlayBackGroundMusic
appdelegate.avAudioPlayer=[[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath] error:&err];
[appDelegate.avAudioplayer play];
in your settings.h
AppDeleagte *appDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//initialise the audioPlayer object.
appDelegate=[[UIApplication sharedApplication]delegate];
}
you can stop the player by
[appDelegate.avAudioPlayer stop];
You can download the fixed project here
I'm new to objective-c so please bear with this long explanation, I hope it will help other beginners. I have been successfully making some changes to an existing iPad app. However, the original install/update routine has hit the failed to launch in time barrier. The posts here have helped me greatly to understand the problem and which direction(s) to research.
I have compiled a solution from different posts here and elsewhere as I did not find a global line-by-line for beginners solution.
I understand that I need to pull the database init/update out of didFinishLaunchingWithOptions and return from here asap with an instantiated UIViewController that will do the DB stuff off the main thread (thanks to all the posters on the subject).
NOTE that the rootVC that is usually called here cannot init if the data is not ready and intact. So just going async on the DB routine doesn't help me because the rootVC gets there first and bombs out when it doesn't find the data it requires.
i.e. I need to delay the rootVC while we do anything we need to do and in peace. I choose to load the UILaunchImage to be seamless and add a spinner.
The question is:
1) Have I done it correctly so that I will never get bitten and 8badf00d again and especially without adding other side effects? Or should I have done it otherwise, maybe in a wrapper init method of the existing rootVC?
2) What about the dealloc, rootViewController or splashViewController? I would think that it is rather rootViewController by this stage. Confused.
3) It works but is this really replacing (and removing) splashViewController by rootViewController as the rootVC? Or am I piling them up...
BEFORE
RAppDelegate.h
#import <UIKit/UIKit.h>
#import "RDataManager.h"
#import "RRootViewController.h"
#import "RScreenViewController.h"
#interface RAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
RRootViewController *rootViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, readonly) RRootViewController *rootViewController;
#end
RAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[RDataManager sharedManager] updateDatabase]; // This is what takes time...
rootViewController = [[RRootViewController alloc] initAtScreen:kScreenTypeIndex withCar:carId];
rootViewController.wantsFullScreenLayout = YES;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
...
- (void)dealloc
{
[rootViewController.view removeFromSuperview];
[rootViewController release];
[window release];
[super dealloc];
}
AFTER
RAppDelegate.h
#import <UIKit/UIKit.h>
#import "RDataManager.h"
#import "RScreenViewController.h"
#import "RSplashViewController.h"
#interface RAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
RSplashViewController *splashViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, readonly) RSplashViewController *splashViewController;
#end
RAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
splashViewController = [[RSplashViewController alloc] init];
splashViewController.wantsFullScreenLayout = YES;
self.window.rootViewController = splashViewController;
[self.window makeKeyAndVisible];
return YES;
}
...
- (void)dealloc
{
[splashViewController.view removeFromSuperview];
[splashViewController release];
[window release];
[super dealloc];
}
RSplashViewController.h
#import <UIKit/UIKit.h>
#import "RRootViewController.h"
#interface RSplashViewController : UIViewController
{
UIImageView *splashImageView;
RRootViewController *rootViewController;
UIActivityIndicatorView *spinner;
}
#property (nonatomic, retain) UIImageView *splashImageView;
#property (nonatomic, readonly) RRootViewController *rootViewController;
#end
RSplashViewController.m
#import "RSplashViewController.h"
#import "RDataManager.h"
#interface RSplashViewController ()
#end
#implementation RSplashViewController
#synthesize splashImageView;
#synthesize rootViewController;
- (void) loadView
{
CGRect appFrame = [UIInterface frame];
UIView *view = [[UIView alloc] initWithFrame:appFrame];
self.view = view;
[view release];
NSString *splashFile = [[NSBundle mainBundle] pathForResource:#"LaunchImage-jaguar-Landscape~ipad" ofType:#"png"];
UIImage *splashImage = [[UIImage alloc] initWithContentsOfFile:splashFile];
splashImageView = [[UIImageView alloc] initWithImage:splashImage];
[self.view addSubview:splashImageView];
[splashImage release];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
CGRect frame = spinner.frame;
frame.origin.x = CGRectGetMidX(self.view.frame) - CGRectGetWidth(spinner.frame) / 2;
frame.origin.y = 650;
spinner.frame = frame;
spinner.hidesWhenStopped = YES;
[self.view addSubview:spinner];
[spinner startAnimating];
}
- (void) viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// how we stop DB refresh from freezing the main UI thread
dispatch_queue_t updateQueue = dispatch_queue_create("updateDB", NULL);
dispatch_async(updateQueue, ^{
// do our long running process here
[[RDataManager sharedManager] updateDatabase];
// do any UI stuff on the main UI thread
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[splashImageView removeFromSuperview];
rootViewController = [[RRootViewController alloc] initAtScreen:kScreenTypeGarage withCar:nil needSplashScreen:YES];
[self.view addSubview:rootViewController.view];
});
});
dispatch_release(updateQueue);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) dealloc
{
[super dealloc];
}
#end
To answer my questions.
1) Yes this is safe, either with SplashViewController or rootVC init wrapper. Ran it as ad-hoc for 2 minutes no problems. Double checked that the update was indeed running in a separate thread (Xcode debug window pane).
2) Non issue since I moved to a rootVC init wrapper solution and reverted to dealloc'ing rootViewController.
3) Problem solved by 2).
I also managed to reduce the update time by 90% which is the ideal solution anyway, but good to know that I am also safely out of the way of the watchdog timer.
So I got this for loop in a function, but it never gets entered,
for (Window *window in _app.windows) {
NSLog(#"test.");
}
I'm a beginner so where do I start to debug this and see where it goes wrong?
EDIT
This is in another class
(its in a function (loadApp) that I call in my ViewController, like this: self.app = [MyClass loadApp]; , the above code is also in my ViewController.
Window *window = [[Window alloc] initWithName:title subtitle:subtitle number:number ident:ident type:type chapternumber:chapternumber icon:icon text:text img:img question:question answerFormat:answerFormat answerLength:answerLength tip1:tip1 tip2:tip2 tip3:tip3 tip1Answer:tip1Answer tip2Answer:tip2Answer tip3Answer:tip3Answer];
[app.windows addObject:window];
}
return app;
Try the following
if(!_app) {
NSLog(#"app is nil");
}
else if(!_app.windows) {
NSLog(#"windows is nil");
}
else {
NSLog(#"there are %d windows", [_app.windows count]);
}
I suspect you'll see there are 0 windows
You have to make sure you are accessing the same variable. That is the gist of all the other comments and answers you are getting. It needs to be setup something like this. Keep in mind, your app may not be setup exactly like this. This is just a general structure to follow:
//myViewController.h
#import "WindowClass.h"
#import "AppClass.h"
#property (strong, nonatomic) AppClass *app;
//myViewController.m
#import "myViewController.h"
#synthesize app;
(id)init....{
//...init code here
//Synthesized objects must be initialized before they are accessed!
self.app = [[AppClass alloc] init];
return self;
}
(void)loadApp {
WindowClass *aWindow = [[WindowClass alloc] init];
[self.app.windowArray addObject:aWindow];
return;
}
(void)loopFunction {
for (WindowClass *window in self.app.windowArray) {
NSLog(#"test.");
}
return;
}
//AppClass.h
#property (strong, nonatomic) NSArray *windowArray;
//AppClass.m
#import "AppClass.h"
#synthesize windowArray;
I've been following Big Nerd Ranch's iOS Programming Guide (3rd Ed.) to set up my Xcode project which displays a list of my company's products and then a detailed view for each.
I got the app working swimmingly the way I need it to, but I started running into trouble when I tried to fancy up the user experience. Adding a UISplitViewController for iPad has caused me no end of head aches and wasted afternoons.
At the moment I am getting semantic issues reported on my delegate-related code. One in DetailViewController.h and the other in ListViewController.m.
I'll sum up my intent for this code before I post it, but in my inexperience I may miss some subtleties:
AppDelegate allocates UITableViewController (ListViewController class), and UIViewController (DetailViewController class) and then checks for an iPad. If an iPad, it creates a UISplitViewController using an array of the two views. Otherwise it loads ListViewController as the master view.
Before I tried to create the delegate relationship between the two views, the app was building successfully but the iPad UISplitViewController loaded only an empty detail view.
The iphone loaded ListViewController, then selecting a row displayed an empty detail view (DetailViewController). When you return to the TableView, and select the same or another table cell, the correct information would then load into DetailView. This led me to believe that the initial instance of the TableView was not passing on the selection correctly, but that returning to it (reallocating it?) would correct the problem. I was hoping the delegate setup would fix that. Since I can't get that part working I can't test that theory. I just figured I'd mention it.
I've looked around as much as I know how to (the right keywords and search terms elude me) with regards to UISplitViewController questions and tutorials, but they all vary greatly from what I've already set up in my project, either in the behavior of the app or the overall structure of the code. I'd rather not have to start over when I seem to be so close.
I've opened up the BigNerdRanch sample code (which does work) and, as I said, the only differences seem related to the way I want to display my information. At this point I need some help, please, to find what I'm doing wrong.
Thanks in advance!
AppDelegate.m:
#import "ProductFeedAppDelegate.h"
#import "ListViewController.h"
#import "DetailViewController.h"
#implementation ProductFeedAppDelegate
#synthesize window = _window;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ListViewController *lvc = [[ListViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *masterNav = [[UINavigationController alloc] initWithRootViewController:lvc];
DetailViewController *dvc = [[DetailViewController alloc] init];
[lvc setDetailViewController:dvc];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UINavigationController *detailNav = [[UINavigationController alloc] initWithRootViewController:dvc];
NSArray *vcs = [NSArray arrayWithObjects:masterNav, detailNav, nil];
UISplitViewController *svc = [[UISplitViewController alloc] init];
//set delegate
[svc setDelegate:dvc];
[svc setViewControllers:vcs];
[[self window] setRootViewController:svc];
} else {
[[self window] setRootViewController:masterNav];
}
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
//... trimmed out some template code to spare you
#end
`
ListViewController.h:
#import <Foundation/Foundation.h>
#import "ProductItemCell.h"
//#import "ItemStore.h"
#import "DetailViewController.h"
#class DetailViewController;
#class RSSChannel;
#interface ListViewController : UITableViewController
{
RSSChannel *channel;
}
#property (nonatomic, strong) DetailViewController *detailViewController;
-(void)fetchEntries;
#end
//A new protocol named ListViewControllerDelegate
#protocol ListViewControllerDelegate
//Classes that conform to this protocol must implement this method:
- (void)listViewController:(ListViewController *)lvc handleObject:(id)object;
#end
ListViewController.m:
#import "ListViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "DetailViewController.h"
#import "ContactViewController.h"
#import "FeedStore.h"
#implementation ListViewController
#synthesize detailViewController;
- (void)transferBarButtonToViewController:(UIViewController *)vc
{
// Trimming Code
}
- (id)initWithStyle:(UITableViewStyle)style
{
// Trimming Code
}
- (void)showInfo:(id)sender
{
// Create the contact view controller
ContactViewController *contactViewController = [[ContactViewController alloc] init];
if ([self splitViewController]) {
[self transferBarButtonToViewController:contactViewController];
UINavigationController *nvc = [[UINavigationController alloc]
initWithRootViewController:contactViewController];
// Create an array with our nav controller and this new VC's nav controller
NSArray *vcs = [NSArray arrayWithObjects:[self navigationController],
nvc,
nil];
// Grab a pointer to the split view controller
// and reset its view controllers array.
[[self splitViewController] setViewControllers:vcs];
// Make contact view controller the delegate of the split view controller
[[self splitViewController] setDelegate:contactViewController];
// If a row has been selected, deselect it so that a row
// is not selected when viewing the info
NSIndexPath *selectedRow = [[self tableView] indexPathForSelectedRow];
if (selectedRow)
[[self tableView] deselectRowAtIndexPath:selectedRow animated:YES];
} else {
[[self navigationController] pushViewController:contactViewController
animated:YES];
}
// Give the VC the channel object through the protocol message
// [channelViewController listViewController:self handleObject:channel];
}
- (void)viewDidLoad
{
// Trimming Code
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [[channel items] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Trimming Code
}
- (void)fetchEntries
{
// Trimming Code
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (![self splitViewController])
[[self navigationController] pushViewController:detailViewController animated:YES];
else {
[self transferBarButtonToViewController:detailViewController];
// We have to create a new navigation controller, as the old one
// was only retained by the split view controller and is now gone
UINavigationController *nav =
[[UINavigationController alloc] initWithRootViewController:detailViewController];
NSArray *vcs = [NSArray arrayWithObjects:[self navigationController],
nav,
nil];
[[self splitViewController] setViewControllers:vcs];
// Make the detail view controller the delegate of the split view controller
[[self splitViewController] setDelegate:detailViewController];
}
RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
// Next line reports: No visible #interface for 'DetailViewController' declares the selector 'listViewController:handleObject:'
[detailViewController listViewController:self handleObject:item];
}
#end
DetailViewController.h:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "ListViewController.h"
#class RSSItem;
#class Reachability;
#interface DetailViewController : UIViewController <ListViewControllerDelegate> // Cannot find protocol declaration for 'ListViewControllerDelegate'
{
__weak IBOutlet UILabel *nameField;
__weak IBOutlet UITextView *descriptField;
__weak IBOutlet UIImageView *imageView;
__weak IBOutlet UITextView *introtextField;
__weak IBOutlet UIButton *dsButton;
__weak IBOutlet UIButton *aeButton;
__weak IBOutlet UIButton *imButton;
}
-(BOOL)reachable;
#property (nonatomic, strong) RSSItem *item;
#property (nonatomic, strong) UIImage *productImage;
#end
DetailViewController.m:
#import "DetailViewController.h"
#import "RSSItem.h"
#import "RSSChannel.h"
#import "Reachability.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (void)listViewController:(ListViewController *)lvc handleObject:(id)object
{
//RSSItem *item = object; //This was in the example code but if left in the next line reported "Local declaration of 'item' hides instance variable"
// Validate the RSSItem
if (![item isKindOfClass:[RSSItem class]])
return;
[self setItem:item];
[[self navigationItem] setTitle:[item name]];
[nameField setText:[item name]];
[descriptField setText:[item descript]];
[introtextField setText:[item introtext]];
}
#synthesize item;
- (BOOL)reachable{
// Trimming Code
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor whiteColor]];
}
- (void)viewWillAppear:(BOOL)animated
{
if (item){
[super viewWillAppear:animated];
[nameField setText:[item name]];
[descriptField setText:[item descript]];
[introtextField setText:[item introtext]];
// Trimming Code (all the stuff that looks for this or that value and acts upon it)
} else {
// The following appears in the log:
NSLog(#"There's no item selected");
}
}
#end
I think you are running into a problem with the compiler getting confused by having several
#import "DetailViewController.h"
If you remove this import from your ListViewController.h and keep the
#class DetailViewController;
Then I think this will get rid of your compiler problems.
You probably need to add < UISplitViewControllerDelegate > to a couple of your other classes though. Looks like you are setting them as delegates on the split view but not adopting the protocol.
The delegate relationships were not set up 100% correctly. Here is how this was fixed.
In ListViewController.m, added a class extension:
#interface ListViewController() <UISplitViewControllerDelegate>
#end
In ListViewController.h, removed:
#import "DetailViewController.h"
In DetailViewController.h, changed line to:
#interface DetailViewController : UIViewController <ListViewControllerDelegate, UISplitViewControllerDelegate>
In ContactViewController.h, changed line to:
#interface ContactViewController : UIViewController <MFMailComposeViewControllerDelegate, UISplitViewControllerDelegate>
These things cleared all errors. This did not, as I'd hoped in my original post, correct the issue of my item not being passed to the detailViewController, as that problem was a result of using "item" instead of "object" in DetailViewController.m's handleObject statement.
I am trying to make a tab bar application, first i followed This Facebook grap api tutorial and my project was working fine like in picture when I touch to login, display popups
after that I have added only a tab bar and I am lost, No errors but program does not launch facebook login display. I have used breakpoints to understand why program doesnt launch facebook login display but couldnt understand because it just stuck no errors. it has to be something with tab bar.
Now it programs stucks at popin up facebook login display
my app delegate.h
#import <UIKit/UIKit.h>
#class FBFunMe;
#interface FBFunAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UITabBarController *rootController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *rootController;
#end
app delegate.m
#import "FBFunAppDelegate.h"
#import "FBFunMe.h"
#import "FBFunLoginDialog.h"
#implementation FBFunAppDelegate
#synthesize window = _window;
#synthesize rootController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[self.window addSubview:rootController.view];
[self.window makeKeyAndVisible];
return YES;
}
I know rest of the code is working because i have an identical project without tab bar that works fine.
Any suggestion or example code to make it work?
_____-----------EDIT------------________
In app delegate when i try this code it display FBFunLoginDialog which what i need but i still need to this in my login button not in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
because i call some variables and appID and staff in order to login to the Facebook
FBFunLoginDialog *loginController=[[FBFunLoginDialog alloc] init];
[self.window addSubview:rootController.view];
[self.rootController presentModalViewController:loginController animated:YES];
[window makeKeyAndVisible];
return YES;
in FBFunMe.h
#interface FBFunMe :UIViewController <FBFunLoginDialogDelegate,UITextFieldDelegate> {
FBFunLoginDialog *_loginDialog;
UIView *_loginDialogView;
}
in FBFunMe.M
- (IBAction)loginButtonTapped:(id)sender {
NSString *appId = #"3888888883";
NSString *permissions = #"publish_stream";
if (_loginDialog == nil) {
self.loginDialog = [[[FBFunLoginDialog alloc] initWithAppId:appId
requestedPermissions:permissions delegate:self] autorelease];
self.loginDialogView = _loginDialog.view;
}
if (_loginState == LoginStateStartup || _loginState == LoginStateLoggedOut) {
_loginState = LoginStateLoggingIn;
[_loginDialog login];
} else if (_loginState == LoginStateLoggedIn) {
_loginState = LoginStateLoggedOut;
[_loginDialog logout];
}
[self refresh];
}