Apparently, this is a well known issue for react native when upgrading to Xcode 8. I have followed this guide to fix the error I am having, but I still get the following error when my app tries to load a <ScrollView/> component.
[RCTCustomScrollView refreshControl]: unrecognized selector sent to instance 0x16099e00
The code in my RCTScrollView.m that everybody seems to think causes the problem is shown below:
- (void)setRefreshControl:(RCTRefreshControl *)refreshControl
{
if (refreshControl) {
[refreshControl removeFromSuperview];
}
refreshControl = refreshControl;
[self addSubview:refreshControl];
}
- (void)removeReactSubview:(UIView *)subview
{
if ([subview isKindOfClass:[RCTRefreshControl class]]) {
_scrollView.refreshControl = nil;
} else {
RCTAssert(_contentView == subview, #"Attempted to remove non-existent subview");
_contentView = nil;
[subview removeFromSuperview];
}
}
Everything seems to work fine when I run this on a device running iOS 10.1.1, but when I try on a device running 9.3, it crashes when it tries to load a <ScrollView/>.
Important Note
- I am running react native 0.28 and am in a tight situation where I can't upgrade right now, thus I have to make the fixes manually.
I know this is an older post, but for Xcode 8, iOS 9.3 (iPad 2/iPad Mini), React Native 0.24.1, I made this change in RCTScrollView.m as a fix.
#implementation RCTCustomScrollView
{
__weak UIView *_dockedHeaderView;
// Added the following line
RCTRefreshControl *_refreshControl;
}
// Also added this
#synthesize refreshControl = _refreshControl;
The only solution I found is this, go to RCTScrollView.m and replace [_scrollView refreshControl] with [_scrollView respondsToSelector: #selector(refreshControl)]
- (NSArray<UIView *> *)reactSubviews
{
if (_contentView && [_scrollView respondsToSelector: #selector(refreshControl)]) {
return #[_contentView, [_scrollView refreshControl]];
}
return _contentView ? #[_contentView] : #[];
}
Related
My code runs perfectly fine on iOS 10.3.3, whereas when I run the same code on iOS 11.2.1, it causes a crash at launch time with the following error:
Assertion failure in -[_UINavigationBarVisualProviderModernIOS _contentViewFittingHeight], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3698.33.7/_UINavigationBarVisualProviderModernIOS.m:569
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Sigh. Contentview size is zero.'
I cleaned the code, cleared the derived data, but those did not solve the issue.
There was an issue in the library I was using for Slide menu "iOS-Slide-Menu". So, I simply changed this two very methods in the library which then worked fine.
- (void)setup
{
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"ssidName"];
[[NSUserDefaults standardUserDefaults] synchronize];
if (singletonInstance)
NSLog(#"Singleton instance already exists. You can only instantiate one instance of SlideNavigationController. This could cause major issues");
singletonInstance = self;
self.menuRevealAnimationDuration = MENU_SLIDE_ANIMATION_DURATION;
self.menuRevealAnimationOption = MENU_SLIDE_ANIMATION_OPTION;
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Update shadow size of enabled
if (self.enableShadow)
self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
self.landscapeSlideOffset = self.view.frame.size.width/6;
self.portraitSlideOffset = self.view.frame.size.width/6;
self.panGestureSideOffset = 0;
self.avoidSwitchingToSameClassViewController = YES;
self.enableShadow = YES;
self.enableSwipeGesture = NO;
self.delegate = self;
// When menu open we disable user interaction
// When rotates we want to make sure that userInteraction is enabled again
[self enableTapGestureToCloseMenu:NO];
if (self.menuNeedsLayout)
{
[self updateMenuFrameAndTransformAccordingToOrientation];
// Handle different horizontal/vertical slideOffset during rotation
// On iOS below 8 we just close the menu, iOS8 handles rotation better so we support keepiong the menu open
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0") && [self isMenuOpen])
{
Menu menu = (self.horizontalLocation > 0) ? MenuLeft : MenuRight;
[self openMenu:menu withDuration:0 andCompletion:nil];
}
self.menuNeedsLayout = NO;
}
}
Fixed out, that two lines must be in viewWillLayoutSubviews instead of setup method. And like #Ishika said, this is the problem of iOS-Slide-Menu.
self.enableShadow = YES;
self.enableSwipeGesture = YES;
This error occured to me with Xcode 10.2.1 and SideMenu 6.0.4. I ended up configuring the navigation controller programmatically, which solved the issue.
let sideMenuVc = UISideMenuNavigationController(rootViewController: <view controller>)
I'm using the pod iOS-Slide-Menu repo in one of my personal projects.
If I run my project on iOS < 11 everything works as expected: When the side menu (blue view controller), touching outside it, i.e. the green part. Automatically closes it
But running on a device with iOS 11 the menu does't get closed when tapping outside.
Another curious situation is that this only happen with recently compiled versions (currently using Xcode 9.0), running the App Store version on a iOS11 device also works correctly.
So my questions are:
Why is this happening?
How can I avoid this to happen without replacing the whole library?
I created a SAMPLE PROJECT in github to reproduce the problem.
In your SlideNavigationController.m file go to viewWillLayoutSubviews method and remove or comment below line
[self enableTapGestureToCloseMenu:NO];
It is because viewWillLayoutSubviews method gets called in ios 11 initially!
so, from viewWillLayoutSubviews, enableTapGestureToCloseMenu gets called and it is removing gesture recognizer from right menu!
Hello #Adrime i have downloaded your code and tested in Xcode 9.0
found same issue like you have. outside tapped not closed view.
after seeing library i have found one solution.
In SlideNavigationController.m file,
one method is already created which is - (void)enableTapGestureToCloseMenu:(BOOL)enable
in that method, just comment this one line [self.view removeGestureRecognizer:self.tapRecognizer];
and your problem is solved.
this line removedGesture of tapping outside.
Updated:
I got it what you want, just change your viewWillLayoutSubviews method
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Update shadow size of enabled
if (self.enableShadow)
self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
// When menu open we disable user interaction
// When rotates we want to make sure that userInteraction is enabled again
//[self enableTapGestureToCloseMenu:NO];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
self.interactivePopGestureRecognizer.enabled = YES;
self.topViewController.view.userInteractionEnabled = YES;
if (self.menuNeedsLayout)
{
[self updateMenuFrameAndTransformAccordingToOrientation];
// Handle different horizontal/vertical slideOffset during rotation
// On iOS below 8 we just close the menu, iOS8 handles rotation better so we support keepiong the menu open
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0") && [self isMenuOpen])
{
Menu menu = (self.horizontalLocation > 0) ? MenuLeft : MenuRight;
[self openMenu:menu withDuration:0 andCompletion:nil];
}
self.menuNeedsLayout = NO;
}
}
What I Did : Do comment //[self enableTapGestureToCloseMenu:NO]; code and put below code
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
self.interactivePopGestureRecognizer.enabled = YES;
self.topViewController.view.userInteractionEnabled = YES;
OLD:
It's Because in SlideNavigationController.m file you are calling [self enableTapGestureToCloseMenu:NO];
Just remove it or make condition for iOS 11 to pass YES for all
For EX.
if (IOS_VERSION == 11) {
[self enableTapGestureToCloseMenu:YES];
}
else {
[self enableTapGestureToCloseMenu:NO];
}
Because when you open your slide menu or click on green area alway call
[self enableTapGestureToCloseMenu:NO];
So as per method code
- (void)enableTapGestureToCloseMenu:(BOOL)enable
{
if (enable)
{
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
self.interactivePopGestureRecognizer.enabled = NO;
self.topViewController.view.userInteractionEnabled = NO;
[self.view addGestureRecognizer:self.tapRecognizer];
}
else
{
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
self.interactivePopGestureRecognizer.enabled = YES;
self.topViewController.view.userInteractionEnabled = YES;
[self.view removeGestureRecognizer:self.tapRecognizer];
}
}
It's removeGestureRecognizer for view.
I'm using DAKeyboardControll on my app .
it has a method with name : swizzled_addSubview and implement Like this:
- (void)swizzled_addSubview:(UIView *)subview
{
if (!subview.inputAccessoryView)
{
if ([subview isKindOfClass:[UITextField class]])
{
UITextField *textField = (UITextField *)subview;
if ([textField respondsToSelector:#selector(setInputAccessoryView:)])
{
UIView *nullView = [[UIView alloc] initWithFrame:CGRectZero];
nullView.backgroundColor = [UIColor clearColor];
textField.inputAccessoryView = nullView;
}
}
else if ([subview isKindOfClass:[UITextView class]]) {
UITextView *textView = (UITextView *)subview;
if ([textView respondsToSelector:#selector(setInputAccessoryView:)] && [textView respondsToSelector:#selector(isEditable)] && textView.isEditable)
{
UIView *nullView = [[UIView alloc] initWithFrame:CGRectZero];
nullView.backgroundColor = [UIColor clearColor];
textView.inputAccessoryView = nullView;
}
}
}
[self swizzled_addSubview:subview];
}
problem
recently in my new version that compatible with AutoLayout , i receive some crash on this method , and reasons of them :
-[UIView(DAKeyboardControl) swizzled_addSubview:] ,
EXC_BAD_ACCESS KERN_PROTECTION_FAILURE at 0x0090dffc
i know this problem has happened for many many call , but why it can't work correctly ?
this crash happened only for 8 users for 54 times , 50 % of them has a jailbreak Device , but another person has a non- jailbreak Device !
Method swizzling causes issues at run time. I also got same kind of exception, To get rid of this, I have used BABFrameObservingInputAccessoryView, which is working fine for me. https://github.com/brynbodayle/BABFrameObservingInputAccessoryView
Most likely your method isn't actually swizzled, so you get a recursive call which will obviously crash. That's the tricky thing about swizzling: It exchanges two methods, so every call to addSubview would call swizzled_addSubview and the call to swizzled_addSubview actually calls addSubview.
- (void)preventGADBannerViewBounceScrolling:(GADBannerView*)bannerView {
for (UIWebView *webView in bannerView.subviews) {
if ([webView isKindOfClass:[UIWebView class]]) {
webView.scrollView.scrollEnabled = NO;
webView.scrollView.bounces = NO;
}
}
}
I have been using the above code to stop the AdMob banner from scrolling.
I just updated the SDK to the latest (6.12.0) and having this code and calling it with the following...
[self.view addSubview:self.adMobBannerView];
[self preventGADBannerViewBounceScrolling:(GADBannerView *)_adMobBannerView];
Does nothing on the latest SDK, I was wondering if anyone has had this issue and resolved it?
Also when on this subject, I have noticed some developers have made their banners so if the user clicks then it opens up in a web view within the application and has a "Done" button at the right hand corner so the user does not fully leave the application when they press on the in-app adverts, I think that is genius...
If anyone could tell me how that is done I would appreciate that greatly!
It looks like UIWebView is wrapped into one more view in the new SDK, so it's better to go through the whole subview tree:
- (void)walkSubviewsOfView:(UIView *)v block:(void (^)(UIView *))block {
block(v);
for (UIView *subview in v.subviews) {
[self walkSubviewsOfView:subview block:block];
}
}
- (void)disableBannerWebViewBouncing {
[self walkSubviewsOfView:_bannerView block:^(UIView *v) {
for (UIGestureRecognizer *r in v.gestureRecognizers) {
if ([NSStringFromClass(r.class) isEqual:#"UIWebTouchEventsGestureRecognizer"])
r.enabled = NO;
}
if ([v isKindOfClass:[UIScrollView class]])
((UIScrollView *)v).bounces = NO;
}];
}
Of course this is not a future proof solution as well, I'd prefer there would be a corresponding property in the SDK.
I went with a non-block version of aleh's answer, I found it easier to read:
- (void)removeScrollingFromView:(UIView *)view
{
for (UIView *subview in view.subviews) {
[self removeScrollingFromView:subview];
}
if ([view isKindOfClass:[UIWebView class]]) {
((UIWebView *)view).scrollView.scrollEnabled = NO;
((UIWebView *)view).scrollView.bounces = NO;
}
}
I know I won't have any scrolling ads, but if you do, just disable bouncing and not scrolling. If you vote up my answer, please consider giving aleh a vote up too!
I've developed a game for iPhone starting from iOS 6.0.
It works fine on my 5S running on iOS 7.1 but when testing it on my old 3GS with iOS 6.1.3, it crash with a "EXC_BAD_ACCESS code:0" when trying to remove some custom UIView from superview.
I logged my custom view and it's superview (that are not nil), but nothing to do it work !
Also tried logging my views and superviews with lldb command and it confirms they are not nil.
Any idea ?? Can't understand how it could work on iOS7 and not on iOS6 !
Here the code when I get the error :
- (void)didMoveToParentViewController:(UIViewController *)parent{
if(parent == nil){
for (LevelNumberView *button in self.levelButtons) {
if(self.view && [self.view.subviews containsObject:button]){
NSLog(#"-- button:%#", button);
[button removeFromSuperview];
}
}
self.levelButtons = nil;
[self.titleView removeFromSuperview];
self.titleView = nil;
[self.view removeFromSuperview];
self.delegate = nil;
}
}
You should be able to call removeFromSuperview on any valid UIView (whether it has a superview or not) so that should not cause an error. My guess would be one of the pointers (that is not nil) is pointing to a released object.
I fix the same issue using check the superview before remove it :
if(self.loadingView.superview){
[self.loadingView removeFromSuperview];
}