I've a big problem with a scrollView. I have this code and when i press a button that is in the xib file of "registerView" then the app crashes:
MainViewController.m:
ViewDidLoad:
UIScrollView* scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
scrollView.backgroundColor = [UIColor whiteColor];
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = NO;
scrollView.showsVerticalScrollIndicator = YES;
scrollView.showsHorizontalScrollIndicator = YES;
scrollView.contentSize = CGSizeMake(768, 1900);
[self.view addSubview:scrollView];
RegisterViewController *registerView = [[RegisterViewController alloc] init];
[scrollView addSubview:registerView.view];
"RegisterView" is added to a scrollView, but then when I push a button in "registerView" the app crashes with this log:
2014-05-12 11:18:04.599 RegisterForm[16505:60b] -[UIScrollView modalPresentationStyle]: unrecognized selector sent to instance 0x13f517200
2014-05-12 11:18:04.602 RegisterForm[16505:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIScrollView modalPresentationStyle]: unrecognized selector sent to instance 0x13f517200'
*** First throw call stack:
(0x18a83709c 0x196c8dd78 0x18a83bd14 0x18a839a7c 0x18a7594ac 0x18d800a68 0x1000e76b4 0x18d70c2c0 0x18d70c044 0x18d7137dc 0x18d710ab0 0x18d78488c 0x1000e674c 0x18d7815cc 0x18d780fb8 0x18d77a9a0 0x18d70d530 0x18d70c720 0x18d77a0b0 0x190119128 0x190118c54 0x18a7f6fc8 0x18a7f6f28 0x18a7f514c 0x18a735b38 0x18d7792d4 0x18d7740e8 0x1000e7cd0 0x197277aa0)
libc++abi.dylib: terminating with uncaught exception of type NSException
Button:
RegisterViewController.h:
- (IBAction)btn_reset:(id)sender;
RegisterViewController.m:
- (IBAction)btn_reset:(id)sender {
}
And I've tried to put a button in the scrollView instead but then i cant access to "textfields" info, so I need to put a button in the "RegisterView".
Declare the RegisterViewController *registerView in #interface or create a #property for it.
#interface XXXXX ()
{
RegisterView *registerView;
}
OR
#property (nonatomic, strong) RegisterView *registerView;
In your case MainViewController is not retaining registerView object. For retaining the instance you need to add it as the childViewController of your MainViewController,
RegisterViewController *registerView = [[RegisterViewController alloc] init];
[self addChildViewController:registerView];
[scrollView addSubview:registerView.view];
No need of declaring any additional properties just for that, UIViewController will retain all its childViewControllers.
I'm guessing that its related to not retaining the "RegisterView" class. While you are adding its view to scrollView the class itself is released as soon as the end of the function is reached.
Try declaring your RegisterView class as a property as follows:
#property (nonatomic, strong) RegisterView *registerView;
And to add it in the scroll view:
self.registerView = [[RegisterViewController alloc] init];
[scrollView addSubview:self.registerView.view];
Related
Summary: All I am trying to do is to have a UIControl subclass that shows a UIMenu when pressed and I have read this other question but I am running into a crash when setting the contextMenuinteractionEnabled property to YES.
Similar question: iOS 14 Context Menu from UIView (Not from UIButton or UIBarButtonItem)
I have a UIControl subclass and I am wanting to add a menu to it and for the UIMenu to be shown when single tapping the control. But I keep getting an error when setting the contextMenuInteractionEnabled property to YES.
Here is the control subclass:
#interface MyControl : UIControl
#end
#implementation MyControl
#end
It is just a plain UIControl subclass. Then, I create an instance of that class and set the value of contextMenuInteractionEnabled to YES, as shown here:
MyControl *myControl = [[MyControl alloc] init];
myControl.contextMenuInteractionEnabled = YES; //<-- Thread 1: "Invalid parameter not satisfying: interaction"
But then when running this, I get the following error message:
Error Message
*** Assertion failure in -[MyControl addInteraction:], UIView.m:17965
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: interaction'
Error: NSInternalInconsistencyException
Reason: Invalid parameter not satisfying: interaction
Stack trace:
(
0 CoreFoundation 0x00000001b8181e94 5CDC5D9A-E506-3740-B64E-BB30867B4F1B + 40596
1 libobjc.A.dylib 0x00000001b14b78d8 objc_exception_throw + 60
2 Foundation 0x00000001b2aa5b4c C431ACB6-FE04-3D28-B677-4DE6E1C7D81F + 5528396
3 UIKitCore 0x00000001ba47e5bc 179501B6-0FC2-344A-B969-B4E3961EBE10 + 1349052
4 UIKitCore 0x00000001ba47ea70 179501B6-0FC2-344A-B969-B4E3961EBE10 + 1350256
)
libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: interaction'
terminating with uncaught exception of type NSException
Questions
What is meant by the error message "Invalid parameter not satisfying: interaction"? Where is "interaction" coming from and how could this be fixed?
What am I doing wrong? All I want is a custom UIControl that can display a menu when pressed. That's it.
As a side note, this code works fine for a UIButton instance, so the UIButton class is doing something internal that I am not doing, but I don't know what.
Update 1
Following the answer from #DonMag, I tried this:
MyControl *control = [[MyControl alloc] init];
control.showsMenuAsPrimaryAction = YES;
UIContextMenuInteraction *contextMenuInteraction = [[UIContextMenuInteraction alloc] initWithDelegate:self];
[control addInteraction:contextMenuInteraction];
[self.view addSubview:control];
And this no longer crashes and the menu even shows up if I long press it. But I was hoping to get it to show up like a regular menu, as the primary action for pressing the control. What I am trying to do is to emulate the menu property on UIButton. That would be the most ideal thing is if I could implement a control that has a menu property and then having that menu be available as the primary action.
There's no need to call .contextMenuInteractionEnabled = YES; ...
Here's a quick, complete example:
#import <UIKit/UIKit.h>
#interface MyControl : UIControl
#end
#implementation MyControl
#end
#interface ControlMenuViewController : UIViewController <UIContextMenuInteractionDelegate>
#end
#interface ControlMenuViewController ()
#end
#implementation ControlMenuViewController
- (void)viewDidLoad {
[super viewDidLoad];
MyControl *myControl = [MyControl new];
UIContextMenuInteraction *interaction = [[UIContextMenuInteraction alloc] initWithDelegate:self];
[myControl addInteraction:interaction];
myControl.frame = CGRectMake(100, 200, 200, 50);
myControl.backgroundColor = UIColor.systemRedColor;
[self.view addSubview:myControl];
}
- (nullable UIContextMenuConfiguration *)contextMenuInteraction:(nonnull UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location {
UIContextMenuConfiguration* config = [UIContextMenuConfiguration configurationWithIdentifier:nil
previewProvider:nil
actionProvider:^UIMenu* _Nullable(NSArray<UIMenuElement*>* _Nonnull suggestedActions) {
NSMutableArray* actions = [[NSMutableArray alloc] init];
[actions addObject:[UIAction actionWithTitle:#"Stand!" image:[UIImage systemImageNamed:#"figure.stand"] identifier:nil handler:^(__kindof UIAction* _Nonnull action) {
NSLog(#"Stand!");
//[self performMenuCommandStand];
}]];
[actions addObject:[UIAction actionWithTitle:#"Walk!" image:[UIImage systemImageNamed:#"figure.walk"] identifier:nil handler:^(__kindof UIAction* _Nonnull action) {
NSLog(#"Walk!");
//[self performMenuCommandWalk];
}]];
[actions addObject:[UIAction actionWithTitle:#"Run!" image:[UIImage systemImageNamed:#"figure.run"] identifier:nil handler:^(__kindof UIAction* _Nonnull action) {
NSLog(#"Run!");
//[self performMenuCommandRun];
}]];
UIMenu* menu = [UIMenu menuWithTitle:#"" children:actions];
return menu;
}];
return config;
}
#end
Edit
Slight modification to allow single-tap (Primary Action):
#import <UIKit/UIKit.h>
#interface MyControl : UIControl
#property (strong, nonatomic) UIContextMenuConfiguration *menuCfg;
#end
#implementation MyControl
- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location {
return self.menuCfg;
}
#end
#interface ControlMenuViewController : UIViewController
#end
#interface ControlMenuViewController ()
#end
#implementation ControlMenuViewController
- (void)viewDidLoad {
[super viewDidLoad];
MyControl *myControl = [MyControl new];
myControl.frame = CGRectMake(100, 200, 200, 50);
myControl.backgroundColor = UIColor.systemRedColor;
[self.view addSubview:myControl];
// menu configuration
UIContextMenuConfiguration* config = [UIContextMenuConfiguration configurationWithIdentifier:nil
previewProvider:nil
actionProvider:^UIMenu* _Nullable(NSArray<UIMenuElement*>* _Nonnull suggestedActions) {
NSMutableArray* actions = [[NSMutableArray alloc] init];
[actions addObject:[UIAction actionWithTitle:#"Stand!" image:[UIImage systemImageNamed:#"figure.stand"] identifier:nil handler:^(__kindof UIAction* _Nonnull action) {
NSLog(#"Stand!");
//[self performMenuCommandStand];
}]];
[actions addObject:[UIAction actionWithTitle:#"Walk!" image:[UIImage systemImageNamed:#"figure.walk"] identifier:nil handler:^(__kindof UIAction* _Nonnull action) {
NSLog(#"Walk!");
//[self performMenuCommandWalk];
}]];
[actions addObject:[UIAction actionWithTitle:#"Run!" image:[UIImage systemImageNamed:#"figure.run"] identifier:nil handler:^(__kindof UIAction* _Nonnull action) {
NSLog(#"Run!");
//[self performMenuCommandRun];
}]];
UIMenu* menu = [UIMenu menuWithTitle:#"" children:actions];
return menu;
}];
// set custom control menu configuration
myControl.menuCfg = config;
// show menu on single-tap (instead of long-press)
[myControl setContextMenuInteractionEnabled:YES];
myControl.showsMenuAsPrimaryAction = YES;
}
#end
My application support is iPad only.
I have UISplitViewController in it.
Left Menu
UIViewController
UITableView
UITableViewCell
UILabel (Added UITapGestureRecognizer)
UIImageView
Center View
UIViewController
UIView
I'm Showing the popover when user taps on UserName label (Left menu -> Tableview -> Cell -> Label)
So my code in cellForRowAtIndexPath method is below.
__weak LeftMenuUserTCell *weakCell = cell;
cell.didTapProfileOption = ^{
NSLog(#"Option Tapped");
[self showMyProfilePopupFrom:weakCell.lblUserName inView:weakCell.lblUserName.superview];
};
and i'm presenting popover like this
-(void)showMyProfilePopupFrom:(UIView *)sourceView inView:(UIView *)parentView
{
ListViewController *listView=[[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ListViewController"];
listView.listDelegate=self;
NSArray *optionList=#[#"My Profile",#"Change Password",#"Sign Out"];
listView.dataArray=[optionList mutableCopy];
listView.selectedItemIndex = -1;
listView.listType = 1;
listView.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popover = listView.popoverPresentationController;
listView.preferredContentSize = CGSizeMake(200, 150);
//popover.delegate = self;
popover.sourceView = sourceView;
popover.sourceRect = sourceView.bounds;
popover.permittedArrowDirections = UIPopoverArrowDirectionUp;
[self presentViewController:listView animated:YES completion:nil];
}
Till now everything is working fine.
Now I have to keep hidden left menu by default so i wrote following code in AppDelegate where i'm setting up UISplitViewController.
self.rootSplitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
Now Problem is my app is crashing when i tap the mentioned label. I have checked that my application is even not crashing when i comment out the above line (UISplitViewControllerDisplayModePrimaryHidden).
Following is the crash log :
MyApp[785:371642] invalid mode 'kCFRunLoopCommonModes' provided to
CFRunLoopRunSpecific - break on
_CFRunLoopError_RunCalledWithInvalidMode to debug. This message will only appear once per execution.
MyApp[785:371642] * Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '* -[__NSPlaceholderDictionary
initWithObjects:forKeys:count:]: attempt to insert nil object from
objects[0]'
Testing on iPad Air (iOS 10.3.3)
I am trying to subclass UIView as BottomNavBar (code below).
I get the following error
'-[UIView setCenterImage:]: unrecognized selector sent to instance 0x14dc5050'
setting a couple of breakpoints the error comes from this line
self.centerImage=[UIImage imageNamed:#"icon_OK.png"]; //I used it just for testing it should be as follows:
self.centerImage=centerIcon;
BottomNavBar.m
- (id)initWithFrame:(CGRect)frame centerIcon:(UIImage*)centerIcon withFrame:(CGRect)centerFrame
{
self = [super initWithFrame:frame];
if (self) {
self=[[UIView alloc]initWithFrame:frame];
[self setBackgroundColor:UA_NAV_BAR_COLOR];
//--------------------------------------------------
self.centerImage=[UIImage imageNamed:#"icon_OK.png"]; //for testing
//self.centerImage=centerIcon; >>this is the one that should be used
self.centerImageView=[[UIImageView alloc]initWithFrame:centerFrame];
self.centerImageView.image=self.centerImage;
[self addSubview:self.centerImageView];
}
return self;
}
cropPhoto.m (where I'm trying to show an object of that class...)
CGRect bottomBarFrame = CGRectMake(0, self.view.frame.size.height-UA_BOTTOM_BAR_HEIGHT, self.view.frame.size.width, UA_BOTTOM_BAR_HEIGHT);
NSLog(#"UA_icon_ok: %#", UA_ICON_OK);
self.bottomNavBar = [[BottomNavBar alloc] initWithFrame:bottomBarFrame centerIcon:UA_ICON_OK withFrame:CGRectMake(0, 0, 90, 45)];
[self.view addSubview:self.bottomNavBar];
can anybody help on what's going wrong here?
self=[[UIView alloc]initWithFrame:frame];
Remove this line. Your view is already initialised, now you're replacing the value of self with a plain UIView.
I'm surprised you're not seeing a compiler warning here.
I am trying to change the text and the position of a UILabel from another class.
I have successfully managed to call my -changeLabel method, which is in my FirstViewController class, from my SecondViewController class. Here is the code I have used in my two classes:
SecondViewController:
#import "FirstViewController.h"
#interface SecondViewController ()
#property (nonatomic,strong) FirstViewController *firstViewController;
#end
#implementation SecondViewController
#synthesize firstViewController;
- (IBAction)button:(id)sender {
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
}
FirstViewController:
- (void)changeLabel {
NSLog(#"changeLabel is called!");
label.text = #"New text.";
label.frame = CGRectMake(10, 100, 150, 40);
NSLog(#"%#", label.text);
NSLog(#"%f", label.frame.size.width);
}
The weird thing is that the logger looks like this after pressing the "button" that calls the method:
"2013-12-30 19:24:50.303 MyApp[655:70b] changeLabel is called!"
"2013-12-30 19:24:50.305 MyApp[655:70b] New text."
"2013-12-30 19:24:50.308 MyApp[655:70b] 0.000000"
So it seems the label text change, but it doesn't show up on the screen. And the label width is logged as 0.0.. even though I just set it to 150.
Why is this happening? Am I not able to change frame variables from another class? Is there another way to do this?
IMPORTANT:
As the FirstViewController is the main view controller while the SecondViewController is a side menu, similar to the facebook app:
I want to be able to press a "button" on the SecondViewController(side menu) and call a method in the FirstViewController(main) that changes the position(frame) of a UILabel.
EDIT:
Here is how I created the UILabel:
label = [[UILabel alloc] init];
label.frame = CGRectMake(0, 0, 150, 40);
label.text = #"Text."
[self.view addSubview:label];
I think problem is this. You are calling method from new instance of FirstViewController.
Let assume
1. FirstViewController at stack[0].
2. SecondViewController at stack[1].
If you are navigating or moving from
FirstViewController->SecondViewController
In this case FirstViewController already in memory with some address 0x23ffff.
And in SecondViewController you are again creating new instance of FirstViewController which is point to another address '0x234jurhu`
- (IBAction)button:(id)sender {
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
}
Don't create new instance here.
You can use delegate or NSNotification concept for this.
How are you displaying FirstViewController?
Here is the issue:
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
You creating a new instance of FirstViewController and updating the label text. If your using these VC's in a navigation stack and you pop back to FirstViewController from SecondViewController, you won't see any label change because they are different instances of the class.
If your using FirstViewController as a childViewController of SecondViewController (with naming of them I don't think this what your doing), then in the - (IBAction)button:(id)sender method you don't need to instantiate a new instance of FirstViewController on each button press.
I have figured out a way to do this thanks to "#Gaurav Wadhwani" answer on this question: call method from other class (self issue).
I added this code in my FirstViewController.h:
+ (FirstViewController *)singletonInstance;
And then added this code in my FirstViewController.m
static FirstViewController *_singletonInstance = nil;
+(FirstViewController*)singletonInstance
{
#synchronized([FirstViewController class])
{
if (!_singletonInstance)
_singletonInstance = [[self alloc] init];
return _singletonInstance;
}
return nil;
}
+(id)alloc
{
#synchronized([FirstViewController class])
{
NSAssert(_singletonInstance == nil, #"Attempted to allocate a second instance of a singleton.");
_singletonInstance = [super alloc];
return _singletonInstance;
}
return nil;
}
Then I added this code in my SecondViewController to run the changeLabel method:
[[FirstViewController singletonInstance] changeLabel];
And that seems to work just fine so far. I hope it wont cause any other "problems" in the future, but right now it seems to be perfect.
Try doing this:
[label setNeedsDisplay];
After the last line in changeLabel.
The error is not every time.
i had try to clean and rebuild app,but it is also.
error:
*** Assertion failure in -[UIWindowController
transition:fromViewController:toViewController:target:didEndSelector:],
/SourceCache/UIKit_Sim/UIKit-2372/UIWindowController.m:211
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Attempting to begin a modal transition from
<UINavigationController: 0x9190730> to <UINavigationController: 0x83a9dc0>
while a transition is already in progress. Wait for viewDidAppear/viewDidDisappear
to know the current transition has completed'
*** First throw call stack:
(0x213d012 0x1e85e7e 0x213ce78 0x191bf35 0x10b8d05 0xeb74f3 0xeb7777 0x10be033f
0xeb77b7 0x104f0 0x1e996b0 0x18c6035 0x20c0f3f 0x20c096f 0x20e3734 0x20e2f44
0x20e2e1b 0x36437e3 0x3643668 0xdcd65c 0x1133f2 0x25c5)
libc++abi.dylib: terminate called throwing an exception
BaseController.h:
#class LoginViewController;
#interface BaseController:UIViewController
//...
#end
BaseController.m
#implement BaseController
//...
-(void)showLoginForm
{
UIViewController* loginx =(UIViewController*) [[LoginViewController alloc] init];
UINavigationController* navx = [[UINavigationController alloc] initWithRootViewController:loginx];
[navx.navigationBar setBackgroundImage:[UIImage imageNamed:#"title_bar.png"] forBarMetrics:UIBarMetricsDefault];
//added
//i can use #try to catch it
[self presentModalViewController:navx animated:YES];//<====it is error
[loginx release];
[navx release];
}
LoginViewController:
#interface LoginViewController:BaseController
//...
#end
otherViewController:
i will judge the user is login or not in this controller.if it is not login,i will call showLoginForm
//#interface otherViewController:BaseController
//......
-(void)viewDidLoad
{
//make a thread to call isLogin
}
-(void)isLogin
{
BOOL logined = YES;
//......
if(!logined)//i take this on MainThread,it has error also.
[super showLoginForm];
}
MainViewController:(it is the Main ViewController to show otherViewController)
//#interface MainViewController:BaseController
//......
-(void)buttonAction
{
otherViewController* other = [[otherViewController alloc] init];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:other];
[self presentModalViewController:navigation animated:YES];
//release
}
so ,Who knows how this is going on?
In otherViewController.m you should move the code that calls the isLogin method to
- (void)viewDidAppear:(BOOL)animated
This will make sure that the transition for the presentation of the otherViewController will have finished when [self presentModalViewController:navx animated:YES]; is called.