Rookie question: I am writing a program that will generate a specific string and then display it in a text window in a different view controller. I have been testing to ensure that the code in fact generates the string using NSLog commands and I know the code is working as intended. For some reason it is not transferring across the view controller and I cant figure out why. Any help? Here is a snippet of the code:
CreateStoryViewController.m
- (IBAction)makeStory:(id)sender
{
StoryLine *myStory =[[StoryLine alloc] init];
[myStory setStory];
self.story = myStory.plot;
NSLog(#"story is %#", self.story);//this is generating the correct story string
self.displayStoryController = [[BIDDisplayStoryViewController alloc] initWithNibName:#"DisplayStoryView" bundle:nil];
[self.view insertSubview:self.displayStoryController.view atIndex:1];
}
DisplayStoryViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
BIDCreateStoryViewController *newStory = [[BIDCreateStoryViewController alloc] init];
NSLog(#"newStory.story is %#",newStory.story);//this generates null message
self.storyDisplay.text = newStory.story;
}
This is wrong. You're instantiating a new BIDCreateViewController object inside your second view controller. This is not the same as the original BIDCreateViewController object that pushed your second BIDDisplayStoryViewController.
You need to declare a string property in your BIDDisplayStoryViewController's header file.
Something like
#property (nonatomic, retain /*or strong, if using ARC*/) NSString *storyToDisplay;
Be sure to synthesize this in your implementation file as well.
When you create BIDDisplayStoryViewController inside your first view controller, you need to do it as follows:
self.displayStoryController = [[BIDDisplayStoryViewController alloc] initWithNibName:#"DisplayStoryView" bundle:nil];
self.displayStoryViewController.storyToDisplay = self.story;
Now inside your second view controller you can access this using self.myStory.
While this will solve your problem (and please do understand that it's not my intention to be rude here), I feel that there's a lack of understanding of how iOS (and OOP in general) works.
In your viewDidLoad method you are making a whole new story. This story is totally different from the one you made in the makeStory: method. You should add a StoryLine Property to DisplayStoryViewController.h, and set that after you init your displayStoryController.
make the intended variable a property type at .h file, so the other file can access it
I need to use a UIPopOverController for my iPhone app ,i searched stackoverflow someone said UIPopoverController does not run on iphone iphone device WHY?.when i run on iphone device
i got this error reason: '-[UIPopoverController initWithContentViewController:]
called when not running under UIUserInterfaceIdiomPad.'
-(void)btnSetRemainderTapped:(UIButton *)button
{
setReminderView =[[SetRemainderView alloc]initWithNibName:#"SetRemainderView" bundle:[NSBundle mainBundle]];
setReminderView.contentSizeForViewInPopover = CGSizeMake(setReminderView.view.frame.size.width, setReminderView.view.frame.size.height);
setReminderView.delegate = self;
popOverController = [[UIPopoverController alloc]
initWithContentViewController:setReminderView] ;
CGRect rect = CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/2, 1, 1);
[popOverController presentPopoverFromRect:rect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
can any one help me?
You CAN use popoverController in iPhone apps.
1. Create a category
// UIPopoverController+iPhone.h file
#interface UIPopoverController (iPhone)
+ (BOOL)_popoversDisabled;
#end
// UIPopoverController+iPhone.m file
#implementation UIPopoverController (iPhone)
+ (BOOL)_popoversDisabled {
return NO;
}
#end
2. Import it to your class and use popover in iPhone as usual.
But remember that this is private method and Apple can reject your app. But I know people who use this normally and Apple published their apps.
Edit: As stated by Soberman, since iOS 8 it is possible to present popovers on iPhone using public APIs, so this answer is probably not relevant anymore.
As stated in Apple's documentation on UIPopoverController:
Popover controllers are for use exclusively on iPad devices.
So there is no way to use this class in iPhone application unfortunately. But there are a couple of custom third-party implementations of the functionality provided by UIPopoverController which add iPhone support and more. See https://github.com/50pixels/FPPopover for example.
Edit: There also is another highly customizable popover implementation for both iPhone/iPad worth checking out: https://github.com/nicolaschengdev/WYPopoverController.
Since iOS8 we are now able to create popovers, that will be the same on iPhone, as on iPad, which would be especially awesome for those who make universal apps, thus no need to make separate views or code.
You can get the class as well as demo project here: https://github.com/soberman/ARSPopover
All you need to do is subclass UIViewController, conform to the UIPopoverPresentationControllerDelegate protocol and set desired modalPresentationStyle along with the delegate value:
// This is your CustomPopoverController.m
#interface CustomPopoverController () <UIPopoverPresentationControllerDelegate>
#end
#implementation CustomPopoverController.m
- (instancetype)init {
if (self = [super init]) {
self.modalPresentationStyle = UIModalPresentationPopover;
self.popoverPresentationController.delegate = self;
}
return self;
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone; //You have to specify this particular value in order to make it work on iPhone.
}
Afterwards, instantiate your newly created subclass in the method from which you want to show it and assign two more values to sourceView and sourceRect. It looks like this:
CustomPopoverController *popoverController = [[CustomPopoverController alloc] init];
popoverController.popoverPresentationController.sourceView = sourceView; //The view containing the anchor rectangle for the popover.
popoverController.popoverPresentationController.sourceRect = CGRectMake(384, 40, 0, 0); //The rectangle in the specified view in which to anchor the popover.
[self presentViewController:popoverController animated:YES completion:nil];
And there you have it, nice, neat blurred popover.
So #Sobermans answer didn't really solve the issue from start to finish for me so I want to detail how I got it done using the docs. That being said I do like the idea of using your own presentation controller subclass to manage all of the customisation you want to exhibit.
1. Create your controller to present
The first step is instantiating the controller you want to present:
let vc: UIViewController = ...
vc.modalPresentationStyle = .Popover
vc.preferredContentSize = CGSize(width: CGRectGetWidth(view.bounds)/2, height: 100)
Now we have a controller with the popover presentation style and an arbitrary content size.
2. Implement adaptivePresentationStyleForPresentationController
By default UIPopoverPresentationController will present on full screen on iPhone so to prevent this behaviour you need to force the adaptive presentation style to none.
First we set the delegate of the popover presentation controller
vc.popoverPresentationController.delegate = self;
Then we implement UIPopoverPresentationControllerDelegate
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None;
}
3. Present and configure popup
First we need to call presentViewController and only after that can we configure the popover:
presentViewController(vc, animated:true, completion:nil)
if let popover = vc.popoverPresentationController {
popover.permittedArrowDirections = .Right | .Left
popover.sourceView = button
popover.sourceRect = button.bounds
}
Use a custom popover controller, such as:
https://github.com/sammcewan/WYPopoverController
(this seems to be the best supported one that I have found).
I ended up creating my custom tooltip/popover class.
Can be initalised with any content view and dynamically adjusts it's frame.
Hope it helps.
https://github.com/akeara/AKETooltip
If you want to do it in Swift, I believe the code is the following:
extension UIPopoverController {
class var _popoversDisabled : Bool {
get { return false }
}
}
Edit: It is working in Xcode 6 beta 4 on iPhone with iOs7.1
This is a really interesting (and depressing) thread to read. I can't believe Apple prevents popup dialogs on iPhones, with absolutely no justification.
And, it's true, on iOS 8, if you try to work around this limitation, it'll make your popups appear as a full-screen modal dialog.
The following excellent webpage describes "How Apple Cheats" to let its own iBooks and iTunes apps break its own rules, and allow popups - but just from within their own iPhone apps.
HowAppleCheats
Have a read (warning: it'll make you hate Apple & XCode even more..)
Want to get around the "UIPopoverController called when not running under UIUserInterfaceIdiomPad" error on iOS 8 ?
Simple.
Just go into your .plist file, and change the Bundle ID to "com.apple.itunesu" to make XCode think that your app is actually iTunes.
Then your popup will work fine.
(Sigh.)
The alternative way of doing this is to directly add your UIViewController to your screen.
In this example, I wanted a "helper screen" to appear on top of my iPhone screen. It's a UIViewController, it is stored in it's own .xib file, and it has a few lines to add a pretty border:
- (void)viewDidLoad {
[super viewDidLoad];
// Give our popup a pretty curved border
self.view.layer.borderColor = [[UIColor blueColor] CGColor];
self.view.layer.borderWidth = 1.0;
self.view.layer.cornerRadius = 8;
}
To display it, I simply create an instance of this UIViewController, add it to my screen, then center it:
-(void)showHelperScreen
{
if (self.helperScreen == nil)
{
// Add the popup UIViewController to our screen
self.helperScreen = [[HelperViewController alloc] init];
[self.view addSubview:self.helperScreen.view];
}
// Center the popup in the middle of the screen
CGSize screenSize = [[UIScreen mainScreen] applicationFrame].size;
self.helperScreen.view.center = CGPointMake(screenSize.width/2, screenSize.height/2);
}
Of course, I also needed to add some code to make the popup disappear when the user taps outside of it, but this does at least show that you can (safely) display popups on an iPhone, even if your app isn't specifically called iTunes or iBook.
Voila.
Hope this helps, and if anyone needs me, I'll be back in my safe, happy place (Visual Studio, in other words).
I am working on an iPhone app. Initially, I had my pickerview in the same screen so this was just a one page app. After skinning it i realized that i want the pickerview on it's own separate page. So i did that. However, my pickerview originally would update uilabels and other objects on that same page. How can I have my pickerview access those objects from it's new view?
- (IBAction)ShowPickerAction:(id)sender {
if (self.theView == nil) {
theView = [containerView initWithNibName:#"containerView" bundle:nil];
theView.parentView = self;
}
self.theView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:self.theView animated:YES];
}
That is the method I am using to call my new view. But line 3 of the above code gives me the error "No known class name for selector initWithNibName:bundle". I think that error is related to something that i did wrong in my header file. My new class is called containerView. So i did this in my header:
#interface ViewController : UIViewController {
containerView *theView;
But that gives me the error "Unknown type name containerView" even though i do have a class named containerView!!
Look into uiappdelegate protocol or try passing values to through a static function to the previous page.
Use a delegate to pass information back and forth to the view object that instantiatrd the picker view. You want to keep your code coupling as loose as possible, especially if you might like to drop it into your next project. Using a delegate and/or blocks are some of the best ways.
I am pretty new with Three20. I have followed ray wenderlich's nice introduction to three20 and the examples within the three20 framework. When I click on a thumbnail in a thumbnail view (subclass of TTThumbsViewController) to launch a Details view, a standard Details image view (deployed by TTPhotoViewController or its super class). I would like to use my own implementation of a Details View instead of the default. I put the following code when I initiated the subclass of TTThumbsViewController and TTThumbsViewControllerDelegate method:
- (id)initWithDelegate:(id<TTThumbsViewControllerDelegate>)delegate {
[super initWithDelegate:delegate];
return self;
}
- (void)thumbsViewController: (TTThumbsViewController*)controller
didSelectPhoto: (id<TTPhoto>)photo {
[navigationController.pushViewController:photoDetailViewController
animated:Yes];
}
But the default TTPhotoViewController view still prevail. When I put a NSLog in the delegate method. I coud see the method was called. I think there is another delegate someone already set in TTThumViewController? Can someone recommend a way to display my detail photo view? Is there another thumbs view controller I can use? Any suggestion will be greatly appreciated.
I'm really new to all of this (coding, etc.) but I'll share what I've found. By looking up the definition of ttthumbsviewcontroller, I was able to find the following method(wrong term?):-
- (void)thumbsTableViewCell:(TTThumbsTableViewCell*)cell didSelectPhoto:(id<TTPhoto>)photo {
[_delegate thumbsViewController:self didSelectPhoto:photo];
BOOL shouldNavigate = YES;
if ([_delegate respondsToSelector:#selector(thumbsViewController:shouldNavigateToPhoto:)]) {
shouldNavigate = [_delegate thumbsViewController:self shouldNavigateToPhoto:photo];
}
if (shouldNavigate) {
NSString* URL = [self URLForPhoto:photo];
if (URL) {
TTOpenURLFromView(URL, self.view);
} else {
TTPhotoViewController* controller = [self createPhotoViewController];
controller.centerPhoto = photo;
[self.navigationController pushViewController:controller animated:YES];
}
}
}
In the else statement, I've found this calls the creation of the photoviewcontroller. By recalling this method (?) in the actual body of my own code and changing the body in the else statement I was able to add a custom detail view. Further down the definition of the ttthumbsnailviewcontroller, you can find that the creatPhotoViewController calls for an initiation of the PhotoViewController so calling that method(?) in the body of the code and initializing another view also works.
If someone can explain whether or not this is a good method of doing this (I have a feeling that is not), it would be appreciated. Also why does putting the method in the body of the code override the call there.
Iam a newbiew to iPhone development. Version of my SDK is 2.2
In my code, UIViewController is used to change view dynamically once the app is launched, a method in the UIViewController is called to know which view should be initialized along with parameters, which goes to a 'switch-case' and assign a view to current view according to the parameter, like this:
case 1:
currentView = [[View01 alloc] init];
break;
case 2:
currentView = [[View02 alloc] init];
break;
and outside the switch-case:
[self.view addSubview:currentView.view];
I wonder f can pass a parameter along with initialization, like iniWithNibName or so? I need this because have to manipulate in the leaded view, according to the view from which its called.
Thanks.
One way to approach this is to modify your View01 and View02 classes to include an initWithParam: initialiser.
i.e. add
- (id) initWithParam:(NSString *)myParam;
to the #interface section and add
- (id) initWithParam:(NSString *)myParam {
if (self = [self init]) {
// handle or store 'myParam' somewhere for use later
}
return self;
}
to the #implementation section. Notice how the initWithParam: message internally calls the existing init. Obviously you could change the type, or number of parameters passed in as required.
Another approach would be to provide a property on your view class, so you could do something like the following:
currentView = [[View01 alloc] init];
currentView.myParam = #"SomeValue";
Which approach works the best will depend somewhat on your particular application needs.