I have a problem with a BOOL, when I try to change the value of an another view's BOOL but it is not working.
The declaration of BOOL :
#property (nonatomic, assign) BOOL vuesortie;
Assigning vuesortie in view :
premierview *vcc = [self.storyboard instantiateViewControllerWithIdentifier:#"jeux"];
SWRevealViewController *revealController = self.revealViewController;
premierview *view;// I'm really sorry not to be a robot and do shit
if ([cellchoistxt isEqual: #"Déjà sortie"])
{
[view setVuesortie:YES];
[revealController pushFrontViewController:vcc animated:YES];
} else if ([cellchoistxt isEqual: #"Prochaines sorties"]) {
NSLog(#"////////////////////////////////////////////////");
[view setVuesortie:NO];
[revealController pushFrontViewController:vcc animated:YES];
}
And the code when view is loaded after pushFrontViewController :
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%hhd" , vuesortie); //--> value = 0 in all cases
....
}
premierview *view;
is not initialized.
You have to initizialized your view before (and please use another class name like "PremierView"):
In any case if for premier view you mean your viewController vcc you should to do:
[vcc setVuesortie:YES];
and obviously the class premierview contains the property:
#property (nonatomic, assign) BOOL vuesortie;
You have to study concept of OOP because you must understand that if you want point to the property of your instanced viewController you have to set the value in your vcc object.
Finally please, use correct notation, like for example:
`PremierViewController` and not `premier view`
for 2 reasons:
is not a UIView but a UIViewController and so is correct maintain the end with ViewController rather than View;
use camel notation, so capitalize the first letter of each word.
Looks like you never assign anything to the view variable. When you call [view setVueSortie] the view object is nil.
Related
I have FirstViewController and SecondTableViewController. In SecondTableViewController.m, I create a cell in the cellForRow... method where the cell.textLabel.text is a string from an NSInteger property ("count") of the SecondTableViewController.
I would like a button in FirstViewController to increment the value of count.
I've tried making a property of FirstViewController and then using that:
#property SecondTableViewController *viewController;
and
- (IBAction)buttonTouched:(id)sender {
self.viewController.count++;
[self.viewController.tableView reloadData];
}
But this way isn't working. count is still its original value of zero. I've also reloaded the table in viewWillAppear and still nothing. How can I do this?
Count being used as a property may be where you are going wrong because count is a method that returns the number of objects in an array that is found in foundation framework. Also keep in mind that if you are storing a integer into a string object try storing it in this format.
cell.textlabel.text = [NSString stringWithFormat: #"%i", count];
Hope this helps
Try following
firstViewController.h
#interface DMFirstViewController : UIViewController
#property (nonatomic, strong) DMSecondViewController * secondController;
- (IBAction)buttonPressed:(id)sender;
#end
firstViewController.m
- (IBAction)buttonPressed:(id)sender
{
++self.secondController.count;
[self.navigationController pushViewController:self.secondController animated:YES];
}
secondViewController.h
#property (nonatomic) int count;
secondViewController.m
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"%d", self.count);
}
EDIT
Check out those two images and implement the similar logic and get the solution.
----- END OF NEW EDIT -----
OLD
I think you haven't assigned and allocated memory for SecondTableViewController reference i.e, self.viewController of FirstViewController in its viewDidLoad method i.e,
-(void) viewDidLoad //In FirstViewController
{
self.viewController = [[SecondTableViewController alloc] init];
}
and pushed the same reference on to the stack of navigationController after performing button taps to increase the count of count variable of SecondTableViewController.
If you are not clear, comment.
Just started xcode 5 and xctest. How do I test that a view loads on button press. I have programatically added method that gets called when the rightBarButtonItem is clicked
action:#selector(onSettingsButton)
and in onSettingsButton
-(void) onSettingsButton{
SettingsViewController *svc = [[SettingsViewController alloc] init];
[self.navigationController pushViewController:svc animated:YES];
}
How to write xctest to ensure SettingsViewController brings up the Settings view? Thank you.
You need an interaction test — that is, a test that checks interactions between objects. In this case, you want to test that -pushViewController:animated: is called on the navigation controller with a SettingsViewController. So we want to put a mock object into self.navigationController which we can ask, "Were you called as expected?"
I'll assume a simple name for the class: MyView.
The way I'd do this by hand is to Subclass and Override navigationController. So in my test code, I'd do something like this:
#interface TestableMyView : MyView
#property (nonatomic, strong) id mockNavigationController;
#end
#implementation TestableMyView
- (UINavigationController *)navigationController
{
return mockNavigationController;
}
#end
Now instead of creating a MyView, the test will create a TestableMyView and set its mockNavigationController property.
This mock can be anything, as long as it responds to -pushViewController:animated: and records the arguments. Here's a simple example, by hand:
#interface MockNavigationController : NSObject
#property (nonatomic) int pushViewControllerCount;
#property (nonatomic, strong) UIViewController *pushedViewController;
#property (nonatomic) BOOL wasPushViewControllerAnimated;
#end
#implementation MockNavigationController
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
self.pushViewControllerCount += 1;
self.pushedViewController = viewController;
self.wasPushViewControllerAnimated = animated;
}
#end
Finally, here's a test:
- (void)testOnSettingsButton_ShouldPushSettingsViewController
{
// given
MockNavigationController *mockNav = [[MockNavigationController alloc] init];
TestableMyView *sut = [[TestableMyView alloc] init];
sut.mockNavigationController = mockNav;
// when
[sut onSettingsButton];
// then
XCTAssertEquals(1, mockNav.pushViewControllerCount);
XCTAssertTrue([mockNav.pushedViewController isKindOfClass:[SettingsViewController class]]);
}
These things can be simplified by using mock object frameworks such as OCMock, OCMockito, or Kiwi's mocking. But I think it helps to start by hand first, so that you understand the concepts. Then choose the tools that help. And if you know how to do it by hand, you'll never say, "Mocking framework X doesn't do what I need! I'm stuck!"
Found one way. Maybe there are others ..
- (void)testSettingsViewShowsWhenSettingsButtonIsClicked{
[self.tipViewController onSettingsButton];
id temp = self.tipViewController.navigationController.visibleViewController;
XCTAssertEqual([temp class], [SettingsViewController class], #"Current controller should be Settings view controller");
}
First call the onSettingsButton, which is the same as clicking the button, but not really. Maybe it's okay for this simple test case? How to simulate the actual press?
Then get the current view from the tipviewcontoller which is the rootview of the app and check that it is a SettingsViewController.
I'm trying to change the alpha of an UIButton from another class. The function that is called in set the alpha property of my UIButton is actually called because I've put a NSLog there and I can see how it works. I'd be thankful if you could give me any suggestion.
Here's my current code.
ViewController.h
- (void) setAlphaToButton;
#property (strong, nonatomic) IBOutlet UIButton *myButton;
ViewController.m
#synthesize myButton;
- (void) setAlphaToButton {
myButton.alpha = 0.5;
NSLog(#"Alpha set");
}
ImageViewSubclass.m
- (void) tapDetected:(UITapGestureRecognizer *)tapRecognizer {
ViewController *VC = [[ViewController alloc] init];
[VC setAlphaToButton];
}
And when the image view is pressed, in my console I get: Alpha set. And the button doesn't change.
In your code, an instance of ViewController is alloced and inited, and the method setAlphaToButton is called on it. Then the view controller is released because you have no object retaining it. That's why you don't see any effect; the ViewController instance you call the method on never appears on screen.
It's not clear how your code is supposed to work; do you have an instance of ViewController in existence when tapDetected is called? If this is the case, and this is the ViewController whose button you want to alter the alpha of, then you need to have a reference to that instance of ViewController and call setAlphaToButton on it.
Your view is not loaded at the moment you trying to set alpha! You need to call this method after your viewDidLoad fired. You can force it by calling view, but it's kind of hackand not recommended!
MyViewController *vc = [MyViewController new];
vc.view; // this string will force view loading
[vc setAlphaToButton];
Add a property of uiviewcontroller class in imageviewsubclass as
ImageViewSubclass.h
#propery (nonatomic, retain) uiviewController *parent;
ImageViewSubclass.m
#synthesize parent;
And initialize it with "self" in view controller class when initalize object of imageviewsubclass and add on the view like
ImageViewsubclass *oneObj = [ImageViewsubClass alloc] init];
oneOBj.parent = self;
do the same for all objects of ImageviewsubClass objects.
and in
- (void) tapDetected:(UITapGestureRecognizer *)tapRecognizer {
[parent setAlphaToButton];
}
I´m having problems declarating my own delegate. Well...thats not exactly true: i have it declarated and, when i build the project, the compiler reports no issues. I declarated it in this way:
I made a file (enviarDatos.h) for declare the protocol:
#protocol enviarDatos <NSObject>
- (void)addItemViewController:(NSMutableArray *)item;
#end
In the Vista2.h (ViewController) file I imported the file enviarDatos.h and declared a property:
#property (nonatomic, weak) id <enviarDatos> delegare;
In the Vista2.m (ViewController) file I use the protocol method:
#interface ViewController : UIViewController <enviarDatos> {
And, finally, in the ViewController.m file I implement the delegates method:
- (void)addItemViewController:(NSMutableArray *)ar {
origen = ar;
}
Does anyone see something wrong? the code of the last function its never executing.
Thanks for your help.
EDIT:
What i need is to change an array in ViewController from Vista2 (another viewcontroller)
Then create delegate property in next view(child view) & set it to self in parent view while pushing or showing child view.
ParentView.m
1.Implement protocol methods
- (void)addItemViewController:(NSMutableArray *)ar
{
origen = ar;
}
2.While showing child view
ChildViewController *child = [[ChildViewController alloc] init];
child.delegate = self;
//present child view
ChildView.h
#property (nonatomic, weak) id <enviarDatos> delegare;
ChildView.m
-(void) anyMethod
{
if([self.delegate respondsToSelector:#selector(addItemViewController:)])
{
[self.delegate addItemViewController:mutableArray];
}
}
Ah, it looks like you are declaring the delegate property in the wrong place.
You should declare the property delegate in enviarDatos.h.
#property (nonatomic, weak) id <enviarDatos> delegate;
Then in Vista2.m you will do something like this...
EnviarDatos *myObject = [[EnviarDatos alloc] init];
myObject.delegate = self;
This then sets up the EnviarDatos object and assigns the Vista2 object as the delegate.
Now, in EnviarDatos.m you can run...
[self.delegate addItemViewController:someObjectArray];
And this will then run that code in the Vista2 object.
Delegates are used for calling back to objects that create them (or some other objects). If you create an object and then want to run a method in it then you won't need a delegate.
Can you say at what condition addItemViewController is invoked?
You seem to be on the right track, but are you sure you are setting the delegate as
[yourObject setDelegate: self];
Have you tried debugging it? Does the debugger pause at addItemViewController if you set a breakpoint there? Can you confirm the delegate is not null inside the method? I may post some code but your seems to be right except for the assigning of delegate, I think you should check it.
Using an instance of a UIViewController, is there any way I can find the UIPopoverController being used to present it? I would also want to find the UIViewController that displayed the UIPopoverController in the first place.
I would normally use a delegate or other sort of notification to send a signal from the displayed view controller to the displaying one, but in this case I'm trying to create a reusable custom segue that dismisses the popover and then moves on to another view in the main view.
You would think that this would be simple (the UIViewController even has a private _popoverController property!), but it is not.
The general answer is that you have to save a reference to the UIPopoverController in the UIViewController that it is presenting, at the time the UIViewController is created.
If you are creating the UIPopoverController programmatically, then that's the time to store the reference in your UIViewController subclass.
If you are using Storyboards and Segues, you can get the UIPopoverController out of the segue in the prepareForSegue method:
UIPopoverController* popover = [(UIStoryboardPopoverSegue*)segue popoverController];
Of course, be sure that your segue really is a UIStoryboardPopoverSegue!
My recommendation is to leverage a combination of your own custom property and the private APIs in UIKit. To avoid app store rejection, any private APIs should compile out for release builds, and should be used only to check against your implementation.
First let's build the custom property into a category on UIViewController. This allows some perks in the implementation, and it doesn't require you to go back and derive every class from some custom view controller subclass.
// UIViewController+isPresentedInPopover.h
#import <UIKit/UIKit.h>
#interface UIViewController (isPresentedInPopover)
#property (assign, nonatomic, getter = isPresentedInPopover) BOOL presentedInPopover;
#end
Now for the implementation - we'll be using the Objective C runtime's associated object API to provide the storage for this property. Note that a selector is a nice choice for the unique key used to store the object, as it's automatically uniqued by the compiler and highly unlikely to be used by any other client for this purpose.
// UIViewController+isPresentedInPopover.m
#import "UIViewController+isPresentedInPopover.h"
#import <objc/runtime.h>
#implementation UIViewController (isPresentedInPopover)
- (void)setPresentedInPopover:(BOOL)presentedInPopover
{
objc_setAssociatedObject(self,
#selector(isPresentedInPopover),
[NSNumber numberWithBool:presentedInPopover],
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)isPresentedInPopover
{
NSNumber *wrappedBool = objc_getAssociatedObject(self, #selector(isPresentedInPopover));
BOOL userValue = [wrappedBool boolValue];
return userValue ?: [[self parentViewController] isPresentedInPopover];
}
#end
So there's a convenient side effect of using this as a category - you can call up to the parentViewController and see if that is contained in a popover as well. This way you can set the property on, say, a UINavigationController and all of its child view controllers will respond correctly to isPresentedInPopover. To accomplish this with subclasses, you'd be either trying to set this on every new child view controller, or subclassing navigation controllers, or other horrific things.
More Runtime Magic
There is still more that the Objective C Runtime has to offer for this particular problem, and we can use them to jump into Apple's private implementation details and check your own app against it. For release builds, this extra code will compile out, so no need to worry about the all-seeing eye of Sauron Apple when submitting to the store.
You can see from UIViewController.h that there is an ivar defined as UIPopoverController* _popoverController with #package scope. Luckily this is only enforced by the compiler. Nothing is sacred as far as the runtime is concerned, and it's pretty easy to access that ivar from anywhere. We'll add a debug-only runtime check on each access of the property to make sure we're consistent.
// UIViewController+isPresentedInPopover.m
#import "UIViewController+isPresentedInPopover.h"
#import <objc/runtime.h>
#implementation UIViewController (isPresentedInPopover)
- (void)setPresentedInPopover:(BOOL)presentedInPopover
{
objc_setAssociatedObject(self,
#selector(isPresentedInPopover),
[NSNumber numberWithBool:presentedInPopover],
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)isPresentedInPopover
{
NSNumber *wrappedBool = objc_getAssociatedObject(self, #selector(isPresentedInPopover));
BOOL userValue = [wrappedBool boolValue];
#if DEBUG
Ivar privatePopoverIvar = class_getInstanceVariable([UIViewController class], "_popoverController");
UIPopoverController *popover = object_getIvar(self, privatePopoverIvar);
BOOL privateAPIValue = popover != nil;
if (userValue != privateAPIValue) {
[NSException raise:NSInternalInconsistencyException format:
#"-[%# %#] "
"returning %# "
"while private UIViewController API suggests %#. "
"Did you forget to set 'presentedInPopover'?",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
userValue ? #"YES" : #"NO",
privateAPIValue ? #"YES" : #"NO"];
}
#endif
return userValue ?: [[self parentViewController] isPresentedInPopover];
}
#end
When using the property incorrectly, you'll get a message like this on the console:
2012-09-18 14:28:30.375 MyApp[41551:c07] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Consistency error in -[UINavigationController isPresentedInPopover]: returning NO while private UIViewController API suggests YES. Did you forget to set 'presentedInPopover'?'
...but when compiling with the DEBUG flag off or set to 0, it compiles down to the exact same code as before.
For The Free and the Foolhardy
Maybe you're doing Ad-Hoc/Enterprise/personal builds, or you're sufficiently bold to see just what Apple thinks about this one for the App Store. Either way, here's an implementation that just works using the current runtime and UIViewController - no setting properties needed!
// UIViewController+isPresentedInPopover.h
#import <UIKit/UIKit.h>
#interface UIViewController (isPresentedInPopover)
#property (readonly, assign, nonatomic, getter = isPresentedInPopover) BOOL presentedInPopover;
#end
// UIViewController+isPresentedInPopover.m
#import "UIViewController+isPresentedInPopover.h"
#import <objc/runtime.h>
#implementation UIViewController (isPresentedInPopover)
- (BOOL)isPresentedInPopover
{
Ivar privatePopoverIvar = class_getInstanceVariable([UIViewController class], "_popoverController");
UIPopoverController *popover = object_getIvar(self, privatePopoverIvar);
BOOL privateAPIValue = popover != nil;
return privateAPIValue ?: [[self parentViewController] isPresentedInPopover];
}
#end
Most helpful would probably be to make popover a class variable, so in the .m file of the class that is going to present the popover, do something like this:
#interface ExampleViewController()
#property (nonatomic, strong) UIPopoverController *popover
#end
#implementation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"some segue"])
{
//prevent stacking popovers
if ([self.popover isPopoverVisible])
{
[self.popover dismissPopoverAnimated:YES];
self.popover = nil;
}
[segue.destinationViewController setDelegate:self];
self.popover = [(UIStoryboardPopoverSegue *)segue popoverController];
}
}
#end
As #joey wrote above, Apple eliminated the need for the dummy control in iOS 8 with the popoverPresentationController property defined for UIViewController as the "The nearest ancestor in the view controller hierarchy that is a popover presentation controller. (read-only)".
Here is an example in Swift for a UIPopoverPresentationController-based segue defined on a storyboard. In this case, a button has been added programmatically and can be defined in this way as the pop-over's anchor. The sender could also be a selected UITableViewCell or a view from it.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showCallout" {
let button = sender as UIButton
let calloutViewController = segue.destinationViewController as CalloutViewController
if let popover = calloutViewController.popoverPresentationController {
popover.sourceView = button
popover.sourceRect = button.bounds
}
}
}
Taking off from ndoc's anwser: this answer shows a neater way in iOS 6 to prevent a popover from showing multiple time through segues. The method in the link was the one that worked awesomely for me for preventing popover stacking.
If you JUST want to know if your controller is being presented inside a popover (not interested to get a reference to the popover controller), you can simply do this, without storing variables nor hacking private API's.
-(BOOL)isPresentedInPopover
{
for (UIView *superview = self.view.superview; superview != nil; superview = superview.superview)
{
if ([NSStringFromClass([superview class]) isEqualToString:#"_UIPopoverView"])
return YES;
}
return NO;
}