Creating a global UIView - ios

I am trying to create an application with a feature similar to facebook's chat bubbles.
When the user navigates to a certain page (InCallViewController), they can connect to another person via video chat. When they navigate out of this page after connecting, I would like the video view to stay floating on the screen, but allow them to do what ever they want to do in the app.
In order to do this, I have made an InCallViewController class, which will allow the user to connect with the other person. Once connected, the video is displayed in a view. This view is movable (similar to facebook's chat bubbles) and displays the video chat perfectly, however when I exit the page and go to another page (AccountViewController) in the app, I am unable to keep this view on the screen. I have tried many things, including setting this view as a subview in the later pages. However when I do this, the subview is not displayed.
MyAccountView.m
- (void)viewDidLoad
{
[super viewDidLoad];
InCallViewController *inCallViewController = [[InCallViewController alloc] initWithNibName:#"InCallViewController" bundle:nil];
[self.view addSubview:inCallViewController.previewView];
[self.view bringSubviewToFront:inCallViewController.previewView];
(Do some other set up stuff)
}
InCallViewController.h
#interface InCallViewController : UIViewController <UIAlertViewDelegate>
{
CGPoint currentTouch;
NSArray *viewArray;
AVAudioPlayer *audioPlayer;
}
#property (weak, nonatomic) IBOutlet UIView *previewVideoView;
The previewView is a UIView in the InCallViewController class. This is hooked up in the IB, and works perfectly when in the InCallController class. The problem is, it won't show up when adding it as a subview in another class. I am wondering what I am doing wrong, or if there is a better way to keep the "previewView" remaining on the screen after I exit InCallViewController.
Thanks

You should consider implementing a container viewController. Since iOS6 and xcode 4.5 this has been made pretty straightforward.
The containing viewController can be handling your previewViews which are overlayed over whatever viewController is currently contained in it.
You can compare what you want to achieve with what Apple has achieved with a UInavigationController (also a container view controller): it contains viewController that are happily showing their content, but the navigationController makes sure the navigationBar is always present, for all viewControllers, even during animations.
Apple has some good documentation and even a WWDC session on this.
Hacking your way into [[UIApplication sharedApplication] keyWindow] is extremely poor design, and a blatant violation of the MVC pattern. It works, but it is a hack nonetheless and might give you headaches in the future.

You can add previewView to [[UIApplication sharedApplication] keyWindow] as a subview so that it appears on all your views and above each of them.

Related

iOS: Have UIImagePickerController be the first view using storyboards

I'm building an app where the first view needs to be the picture taking view using UIImagePickerController.
I am able to put a button on the screen and have it load the view when pressed, but how do you make it the initial view that loads? Basically load with out user interaction.
I'm using storyboards and I think the lack of knowledge of how they exactly work is my problem.
Subclass UIImagePickerController in your rootviewcontroller.
#interface MyRootViewController : UIImagePickerController {
}
I bet viewDidLoad and viewWillAppear methods won't work. I think you may have to put it in
-(void) viewDidAppear:(BOOL)animated {
[self presentSomething];
}
There will be a second where you'll just see the viewController before the image picker will come up. Best to account for this by making sure there's a background that's pleasant for that split second.

How to make a class that uses MPMoviePlayerController to play videos from a webserver, without any memory problems

I am really struggling to use custom built classes in Objective C. I can make them fine, but as soon as I use them to do something like play a video (using the MPMoviePlayerController class), I run into memory allocation problems. Ive read and re-read Apples own documentation on memory management, Ive gone through various online tutorials, and I have asked and read many questions on here. But I keep getting the same memory allocation problems time and again.
So far Ive been solving my memory problems by moving all my code into the AppDelegate class (I feel like this is not the right thing to do, I dont want to overload my AppDelegate class). All my properties in the AppDelegate class behave like I would expect.
But as soon as I build a class of my own to deal with a particular task, some of the properties get released unexpectedly (all my properties are being declared as strong, but they are still getting released whilst in use). For example a property holding an object that plays a video gets released while the video is playing. I don't understand how or why this is happening.
I feel that I am doing something fundamentally wrong.
I have been trying to figure this out for some time now, (see my past questions), but no matter what I do I run into EXC_BAD_ACCESS problems, usually because a property that Ive declared to be strong gets released out of my control, when I dont want it to.
I feel bad for asking such an open ended question, but I feel like Ive exhausted ever other option available to me.
Can someone please show me, from scratch, the correct way to make a class that uses MPMoviePlayerController to play videos from a webserver - but most importantly, show me how to do this where there are absolutely no memory problems, at any point. Nothing gets released unexpectedly, and everything is in memory when I need it to be there (i.e. while the video is still playing).
I am sorry to ask this question, but after several months of struggling with this issue, I don't know what else I can do.
Thanks in advance.
To use MPMoviePlayerController correctly, you need to decide when you'd like the video to be playing, how to handle showing and hiding the movie player, and when you'd like things to appear. I'm going to explain one way to do it with a sample project at the end (scroll down for download link). Feel free to use and modify the project to your liking.
The most important part is to declare the MPMoviePlayerController as a property of your custom view controller -- or a custom class used within your custom view controller-- and not to explicitly (or implicitly, through dismissing a view controller, etc.) deallocate the custom class, custom view controller, or MPMoviePlayerController until you're done with them.
Placing all your code in the app delegate is generally not good design. You want to spread your code out so it is modular and easily readable.
Start with a basic XCode project with the .xib that comes with it. Then create a custom view controller (.h for interface, .m for implementation, and .xib file for user interface) by going to File > New > File, selecting Cocoa Touch from the left-hand side, and choosing Objective-C class. Click next, and name the file MyMovieViewController. Check the box "With XIB for user interface".
Now, modify your App Delegate:
In AppDelegate.h, add a property for your custom view controller:
#property (nonatomic, strong) MyMovieViewController
*myMovieViewController;
In AppDelegate.m's -application:didFinishLaunchingWithOptions: function, initialize your custom view controller, and declare a UINavigationController initialized with MyMovieViewController as its "root view controller":
self.myMovieViewController = [MyMovieViewController alloc] initWithNibName:#"MyMovieViewController" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:myMovieViewController];
self.window.rootViewController = nav;
Next, set your application's window's root view controller to this UINavigationController. declare a UINavigationController initialized with your ViewController as its "root view controller". The last line of the app delegate's function should still read:
[self.window makeKeyAndVisible];
Now, to the good stuff. You now have a custom view controller, MyMovieViewController.
In MyMovieViewController.h, give it a MPMoviePlayerController called mpController as a property:
#property (nonatomic, strong) MPMoviePlayerController *mpController;
In MyMovieViewController.m's viewDidLoad function, instantiate mpController:
NSString *urlString =#"..."; //your url here
NSURL *url = [NSURL URLWithString:urlString];
self.mpController = [[MPMoviePlayerController alloc] initWithContentURL:url];
Create two buttons in MyMovieViewController's xib, and link them to -(IBAction)showControllerButtonPressed:(id)sender and -(IBAction)hideControllerButtonPressed:(id)sender, both implemented in the .m file
In -(IBAction)showControllerButtonPressed:(id)sender, add the following:
self.mpController.view.frame = CGRectMake(0,0,320,320); //your size here
[self.view addSubview:self.mpController.view];
[self.mpController prepareToPlay];
[self.mpController play];
This sets the correct size, adds the controller's view as a subview of your custom view controller's view, prepares the movie, and plays it.
In -(IBAction)hideControllerButtonPressed:(id)sender, add the following:
[self.mpController pause];
[self.mpController.view removeFromSuperview];
This pauses the video (so audio and video stop playing) and removes the controller's view from your custom view controller's view.
The property mpController will live in MyMovieViewController for the life of the program, since you added MyMovieViewController as the root view controller of the UINavigationController in the AppDelegate. If you'd like to present and dismiss MyMovieViewController, reloading the movie each time, you should set mpController = nil when you dismiss.
Note that you can also tell mpController to pause and play when the view will appear, disappear, gets backgrounded, etc.
Here's a sample project demonstrating the MPMoviePlayerController as a property of a custom view controller. (Note, this project has one more view controller, used to present and dismiss the view controller containing the MPMoviePlayerController. To ensure that memory is being deallocated properly, run the project using Instruments, with the Allocations instrument. Filter by ViewController, MyMovieViewController, and MPMoviePlayerController to see the relevant classes get allocated and deallocated):
http://www.filedropper.com/examplemovie-xcode5-ios7

How to notify navigation controller it should push a viewcontroller, from a subview of n layers?

I have a view that I want to reuse in different situations. It is a user view that, when touched, will have the viewcontroller push a user detail viewcontroller.
So basically I have a view that can any number of superviews until the viewcontroller. I want that view to be able to notify whatever viewcontroller that is currently being displayed to push the user detail view.
Is there a way besides using NSNotificationCenter to do this? Is NSNotificationCenter my best option? I've tried to put in a protocol/delegate, but that isn't working out for me.
Thanks!
------------------------Response to a comment----------------
I would like to have it so it is dynamic. That is partially my problem. I will use this view throughout my code and when I make updates/changes, I don't want to have to change the actual user view to make things work
An example would be adding this user view on the following hierarchy: viewcontroller->tableview->tableviewcell->userview. But then I'd also like to add it like this: viewcontroller->userview.
navigationController.topViewController may be helpful in this case. Or if your app is using a single navigation stack, you could handle this notification in the appDelegate
#interface AppDelegate
#property (nonatomic, strong) UINavigationController *nav;
...
[nav pushViewController:userVC animated:YES];
I think it does make sense to use an NSNotification in this case. Per MVC, the UIView handling the touch event should not need to know much about the View Controller hierarchy it lives in. Notifications handle that issue.
I am thinking that I will subclass a UINavigationController and register for my NSNotification there, then i won't have to worry about registering on each UIViewController in my app. I'll leave this answer here for a bit without checking it as the answer to see what kind of side effects this might have.

XCode: MasterDetailsView - DetailsView without Splitscreen in Landscape?

actually I'm quite new with Xcode and couldn't find the answer to the following two questions by a google search:
to make it short: I'm working on an iPad app that displays proposals. For this purpose you should choose a proposal from the table in MasterView and then see the details in the DetailsView in landscape mode (but without the MasterView on the Spitscreen).
So when the app starts in landscape mode, I wanna see directly the first proposal full screen on the DetailsView. And when I tap onto the screen the MasterView should popup/unhide with the other proposals in the table. Is this possible?
I wanna display the PDFs in a WebView like in iBooks. That means that the navigation bar is hidden and only when I tap onto the screen the navigation bar should appear at the top of the screen.
I'm kind of sure this questions have been solved somewhere but I couldn't find anything by search so I hope you can help me anyway :-)
Thanks in Advance!
Q1: Use can use one of many methods to present a view (look up under Apple's doc on UIViewController under "Presenting Another View Controller's Content" heading). Two that I have used are: – presentModalViewController:animated: and – presentViewController:animated:completion: (the latter is the latest addition in iOS 5.0)
So let's say you have a detail controller called MyDetailViewController, in your Master View Controller's implementation file (the .m file), under viewDidLoad method, you would do some thing like this to present it as a full screen view.
MyDetailViewController *myDetailViewController = [[MyDetailViewController alloc] initWithNibName:#"MyDetailViewController" bundle:nil];
[myDetailViewController.view setFrame:CGRectMake(0, 0, 1024, 768)]; //might not need this
[self presentViewController:newDetailViewController animated:YES completion:^{
NSLog(#"complete"); //optional
} ];
To dismiss or hide this MyDetailViewController with a tap or touch, you can use UITapGestureRecognizer or touchesEnded method and using one of the dismiss methods (refer back to Apple's UIViewController again for this).
Q2: I personally have not used UIWebView to display PDF and not sure if iBooks is using UIWebview to do it. But to display a varieties of popular documents formats, you can use either the QLPreviewController class or UIDocumentInteractionController. You can hide the toolbar while the document is displayed.
Good luck.

UITabBar with UITableView - I can see the table correctly, but cannot select a row

This may be an easy answer for someone.
I first built an a navigation app that had a table loaded from SQLite. The rootViewController (UITableViewController) is loaded from the mainWindow.xib . I added the search and scope functions, and push a detailed view (UIViewController) from a row selection just fine, and can navigate back and forth to and from the table and filtered results, search, with scoping different searches. All is good, no errors, crashes, or warnings.
Now I have tried to add a tabBar interface on top of the rootViewController...after 2 days I have got the TabBarController to display (I was trying to implement it directly on the RootviewController, but found I had to implement it in the mainWindow) and I can select different views (xib) from the tab bar. I have one tab that has no view assigned to it in IB, and I can see the RootViewController load as it did before as the first screen in this tab view, even though RootViewController is not assigned in the tab.
The problem is I cannot click on a row in the table when it loads this way. Alternatively if I create a tab, calling the RootViewController, I get the search bar on the top, but the table is empty. I feel this is somehow due to my appDelegate loading the rootViewController, and me not knowing how to get it to "load" or "reload" into the tab, or something like this. I tried creating a separate "search.xib" that was identical to the original mainWindow before adding the tab bar, then trying to load that in the TabItem, so it called the appDelegate first, but no cigar: crash. I verified the search.xib works fine, as I put it as the info.plist "Main nib file base name", and this loads fine and works as before this BS of adding a tabBarController...
I would start pasting code, but not sure what someone would need to know what is missing or wrong. I do call [self.tableView reloadData] in -(void)viewDidLoad, in RootViewController.m but it is not helping this problem at all.
Can anyone help?
Mac OS X is version 10.5.8, and I am using XCode 3.1.4.
// Create and configure the main view controller.
RootViewController *rootViewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
rootViewController.violinMakers = violinMakers;
[violinMakers release];
// Add create and configure the navigation controller.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navController = navigationController;
[navigationController release];
// Configure and show the window, Override point for customization after app launch
[window addSubview:[navController view]];
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
Thanks for trying to help!
The last section above appears to be where I should get the RootViewController to be on top of the stack, but not sure how.
// <AppName>AppDelegate.h
#interface <AppName>AppDelegate: NSObject <UIApplicationDelegate,
UITabBarControllerDelegate, UINavigationControllerDelegate>{
UIWindow *window;
UINavigationController *navController;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navController;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
Ben - I do realize what you are saying about the rootViewController being behind the tabBarController. I just don't know how to set the tabBar as the main view, and the navController as a tab of it. I will look at the tutorial you mention and see if that helps explain it. Thanks Ben!
09-10-14 update
Some progress!
I now have the view in the tab with the with the NavBar at the top. I know it is coming from the correct .xib file as the title and the search can now be clicked on, and the scope buttons are the correct names. .... but as before, if I got to this stage or even close, the table information is not loaded into this tab(all cells are blank). How do I get my table to load properly in this cell? I know it is loading on launch, as if there is no view assigned at all to this window, I can see the table n Nav, but cannot click on it.(So close, yet so far away). I now have the tab set up correctly, but the table is not loading properly... rrrr
I have the typical
[self.tableView reloadData];
in the viewController.m in the method:
- (void)viewWillAppear:(BOOL)animated
and in
- (void)viewDidAppear:(BOOL)animated
and in
- (void)viewDidLoad
and tried it some other methods as well, but it is not reloading the table info when I select the tab.
Any ideas on how to reload this table in the TabBar view properly ?
I did find a good tutorial on tabBars that went a bit further than some others in explaining with IB. Twillo Embed Nav in a Tab Tutorial
It would appear that you're adding your tab bar controller on TOP of your table controller. It's not clear where you set up tabBarController, but you should only be adding ONE view to your window (in the third-to-last and second-to-last lines you are adding two).
The basic premise for Navigation and TabBar controllers is that your Tab Bar controller is the primary, and you'll add the Navigation controller as one of its tabs. Then, add the tabBarController.view to your window. Which ever tab is selected will be the visible one.
There's a tutorial posted on the web on this subject.
Basically here is what I have found for those of you with the same problem.
It is not easy, or really suggested by Apple it instantiate a tab bar later in a program. Yes it can be done, but now I would suggest a different method. I found a modal view controller works just a good as a tabBar, abeit smaller, but takes less real-estate, because it can be placed in the navigation bar. If you are planning an app with tabs, start with a tab based app and then customize it, don't try to change the navigation structure later, which is the underlying issue. Secondly I have found Apple's documentation on Interface Builder less than satisfactory. Everyone seams confused and it's implementation limits the actual final product cusomization, not making it easier. Not to mention more confusing on "wiring" all the elements together in it. That really sucks, and I took 2 weeks in trying various methods to make it work. It is not impossible, just incredibly unintuitive, and a mistake on my part to change paddles half way down stream. Look at the alternatives to the way you want to give access to the information, and I think you will find better ways like the modal view to accomplish this, or by simple buttons with IB actions to access different views or further information.
Happy Programming!
Kirk

Resources