ios - আইওএস অ্যাপ্লিকেশন ত্রুটি-সাবউইউ হিসাবে স্ব যোগ করতে পারবেন না




iphone objective-c (12)

আমি এই ক্র্যাশ রিপোর্ট পেয়েছি, কিন্তু আমি এটি ডিবাগ কিভাবে জানি না।

Fatal Exception NSInvalidArgumentException
Can't add self as subview
0 ...    CoreFoundation  __exceptionPreprocess + 130
1    libobjc.A.dylib     objc_exception_throw + 38
2    CoreFoundation  -[NSException initWithCoder:]
3    UIKit   -[UIView(Internal) _addSubview:positioned:relativeTo:] + 110
4    UIKit   -[UIView(Hierarchy) addSubview:] + 30
5    UIKit   __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 1196
6    UIKit   +[UIView(Animation) performWithoutAnimation:] + 72
7    UIKit   -[_UINavigationParallaxTransition animateTransition:] + 732
8    UIKit   -[UINavigationController _startCustomTransition:] + 2616
9    UIKit   -[UINavigationController _startDeferredTransitionIfNeeded:] + 418
10   UIKit   -[UINavigationController __viewWillLayoutSubviews] + 44
11   UIKit   -[UILayoutContainerView layoutSubviews] + 184
12   UIKit   -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 346
13   QuartzCore  -[CALayer layoutSublayers] + 142
14   QuartzCore  CA::Layer::layout_if_needed(CA::Transaction*) + 350
15   QuartzCore  CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16
16   QuartzCore  CA::Context::commit_transaction(CA::Transaction*) + 228
17   QuartzCore  CA::Transaction::commit() + 314
18   QuartzCore  CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 56

আইওএস সংস্করণ 7.0.3। যে কেউ এই অদ্ভুত ক্র্যাশ অভিজ্ঞতা?

হালনাগাদ:

আমি জানি না আমার কোডে এই ক্র্যাশের কারণ কোথায়, তাই আমি এখানে কোড পোস্ট করতে পারছি না, দুঃখিত।

দ্বিতীয় আপডেট

নীচের উত্তর দেখুন।


"AddSubview" এর জন্য আপনার কোড অনুসন্ধান করুন।

আপনি এই পদ্ধতিটির নামগুলির একটিতে এই পদ্ধতি ব্যবহার করে নিজের উপসদৃশ অ্যারেতে একটি দৃশ্য যুক্ত করার চেষ্টা করেছেন।

উদাহরণ স্বরূপ:

[self.view addSubview:self.view];

বা:

[self.myLabel addSubview:self.myLabel];

@ রবপ এর দুর্দান্ত ইঙ্গিতের ভিত্তিতে আমি এই সমস্যাগুলি প্রতিরোধ করতে ইউএনভিভিশন কন্ট্রোলার উপশ্রেণীটি তৈরি করেছি । এটি pushing এবং / বা popping পরিচালনা করে এবং আপনি নিরাপদে চালাতে পারেন:

[self.navigationController pushViewController:vc1 animated:YES];
[self.navigationController pushViewController:vc2 animated:YES];
[self.navigationController pushViewController:vc3 animated:YES];
[self.navigationController popViewControllerAnimated:YES];

যদি 'স্বীকার করা কনফ্লিক্টিং কম্যান্ডস' পতাকাটি সত্য (ডিফল্ট অনুসারে) ব্যবহারকারী ভিসি 1, ভিসি 2, ভিসি 3 এর অ্যানিমেটেড pushing দেখতে পাবে এবং তারপরে ভিসি 3 এর অ্যানিমেটেড পপিং দেখবে। যদি 'স্বীকার করা কনফ্লিক্টিং কম্যান্ডস' মিথ্যা হয় তবে VC1 সম্পূর্ণভাবে ধাক্কা না দেওয়া পর্যন্ত সমস্ত push / pop অনুরোধ বাতিল করা হবে - তাই অন্য 3 টি কল বাতিল করা হবে।


আপনি যদি UiViewController ক্লাস হতে চলেছেন তবে আপনি নিজেকে সাবভিউ হিসাবে যোগ করতে পারবেন না। আপনি যদি UiView ক্লাস হতে চলেছেন তবে আপনি নিজেকে সাবভিউ হিসাবে যুক্ত করতে পারেন।


আপনি যদি কোনও ভিউতে একটি সাবউইউউউউ যুক্ত করতে চান তবে আপনি এটি পছন্দ করতে পারেন;

UIView *mainview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)]; //Creats the mainview
    UIView *subview = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; //Creates the subview, you can use any kind of Views (UIImageView, UIWebView, UIView…)

    [mainview addSubview:subview]; //Adds subview to mainview

আমারও একই সমস্যা ছিল, যা আমার জন্য সহজেই কাজ করেছিল তা অ্যানিমেটেড পরিবর্তন হচ্ছে: হ্যাঁ, অ্যানিমেটেড: না।

দেখে মনে হচ্ছে সমস্যাটি অ্যানিমেশনের কারণে শেষ হয়নি।

এই কেউ সাহায্য করে আশা করি।


আমি আমার অ্যাপে এই ক্র্যাশ সম্পর্কে আরও বিশদ বর্ণনা করব এবং উত্তর হিসাবে চিহ্নিত করব।

আমার অ্যাপটির একটি UINavigationController রয়েছে যা মূল নিয়ামকটি একটি UITableViewController যা নোট বস্তুর একটি তালিকা রয়েছে। নোট বস্তুর HTML এ একটি সামগ্রী সম্পত্তি আছে। একটি নোট বিস্তারিত কন্ট্রোলার যেতে হবে নির্বাচন করুন।

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //get note object
    DetailViewController *controller = [[DetailViewController alloc] initWithNote:note];
    [self.navigationController pushViewController:controller animated:YES];
}

বিস্তারিত নিয়ামক

এই নিয়ামকটির একটি UIWebView রয়েছে, রুট নিয়ামক থেকে প্রেরিত নোট সামগ্রী প্রদর্শন করুন।

- (void)viewDidLoad
{
    ...
    [_webView loadHTMLString:note.content baseURL:nil];
    ...
}

এই নিয়ামক ওয়েবউইউ কন্ট্রোল প্রতিনিধি। নোট লিঙ্ক থাকে, একটি লিঙ্ক ইন-অ্যাপ্লিকেশন ওয়েব ব্রাউজার যেতে হবে।

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    WebBrowserViewController *browserController = [[WebBrowserViewController alloc] init];
    browserController.startupURL = request.URL;
    [self.navigationController pushViewController:webViewController animated:YES];
    return NO;
}

আমি প্রতিদিন উপরে ক্র্যাশ রিপোর্ট পেয়েছি। আমার কোড এই ক্র্যাশ কারণ যেখানে আমি জানি না। কিছু ব্যবহারকারীর সহায়তায় তদন্তের পর, আমি অবশেষে এই ক্র্যাশটি ঠিক করতে সক্ষম হয়েছিলাম। এই এইচটিএমএল কন্টেন্ট ক্র্যাশ হতে হবে:

...
<iframe src="http://google.com"></iframe>
...

বিস্তারিত কন্ট্রোলারের ডিডলড পদ্ধতিতে, আমি এই HTML টি ওয়েবউইউ কন্ট্রোলে লোড করেছি, তারপরে তারপরে, উপরের প্রতিনিধি পদ্ধতিটি অনুরোধের সাথে অবিলম্বে বলা হয়। URL হল iframe এর উৎস (google.com)। ViewDidLoad => ক্র্যাশে যখন এই প্রতিনিধি পদ্ধতি pushViewController পদ্ধতি কল করে!

আমি নেভিগেট টাইপ করে এই ক্র্যাশটি সংশোধন করেছি:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if (navigationType != UIWebViewNavigationTypeOther)
    {
        //go to web browser controller
    }
}

আশাকরি এটা সাহায্য করবে


আমি যে কোনও সময়ে অ্যানিমেশন সহ pushing / popping ভিউ কন্ট্রোলার পুরোপুরি জরিমানা হওয়া উচিত এবং SDK অনুগ্রহপূর্বক আমাদের জন্য কলগুলির সারি পরিচালনা করতে হবে।

তাই এটি এবং সমস্ত সমাধান পরবর্তী ধাক্কাগুলি উপেক্ষা করার চেষ্টা করে না, যা কোনও বাগ হিসাবে বিবেচনা করা যেতে পারে যেহেতু চূড়ান্ত ন্যাভিগেশন স্ট্যাকটি কোডটির উদ্দেশ্যে নয়।

আমি পরিবর্তে একটি ধাক্কা কল সারি বাস্তবায়িত:

// SafeNavigationController.h

@interface SafeNavigationController : UINavigationController
@end

// SafeNavigationController.m

#define timeToWaitBetweenAnimations 0.5

@interface SafeNavigationController ()

@property (nonatomic, strong) NSMutableArray * controllersQueue;
@property (nonatomic)         BOOL animateLastQueuedController;
@property (nonatomic)         BOOL pushScheduled;
@property (nonatomic, strong) NSDate * lastAnimatedPushDate;

@end

@implementation SafeNavigationController

- (void)awakeFromNib
{
    [super awakeFromNib];

    self.controllersQueue = [NSMutableArray array];
}

- (void)pushViewController:(UIViewController *)viewController
                  animated:(BOOL)animated
{
    [self.controllersQueue addObject:viewController];
    self.animateLastQueuedController = animated;

    if (self.pushScheduled)
        return;

    // Wait for push animation to finish
    NSTimeInterval timeToWait = self.lastAnimatedPushDate ? timeToWaitBetweenAnimations + [self.lastAnimatedPushDate timeIntervalSinceNow] : 0.0;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((timeToWait > 0.0 ? timeToWait : 0.0) * NSEC_PER_SEC)),
                   dispatch_get_main_queue(), ^
                   {
                       [self pushQueuedControllers];

                       self.lastAnimatedPushDate = self.animateLastQueuedController ? [NSDate date] : nil;
                       self.pushScheduled = NO;
                   });
    self.pushScheduled = YES;
}

- (void)pushQueuedControllers
{
    for (NSInteger index = 0; index < (NSInteger)self.controllersQueue.count - 1; index++)
    {
        [super pushViewController:self.controllersQueue[index]
                         animated:NO];
    }
    [super pushViewController:self.controllersQueue.lastObject
                     animated:self.animateLastQueuedController];

    [self.controllersQueue removeAllObjects];
}

@end

এটি ধাক্কা এবং pops মিশ্র queues হাতল না কিন্তু এটি আমাদের ক্র্যাশ সবচেয়ে সংশোধন করার জন্য একটি ভাল স্টার্টার।

জিস্টঃ https://gist.github.com/rivera-ernesto/0bc628be1e24ff5704ae


আমি সম্প্রতি ডিবাগ করেছি এমন কিছুর উপর ভিত্তি করে অনুমান করছি ... যদি আপনি অ্যানিমেটেড দিয়ে দৃশ্য নিয়ামকটি ধাক্কা দেন (অথবা পপ): হ্যাঁ এটি এখন সম্পূর্ণভাবে সম্পন্ন হয় না এবং যদি আপনি অ্যানিমেশনের আগে অন্য ধাক্কা বা পপ করেন তবে খারাপ জিনিস ঘটবে। সমাপ্ত হবে। আপনি সহজেই পরীক্ষা করতে পারেন যে এটি আপনার পিশ এবং পপ ক্রিয়াকলাপগুলিকে অস্থায়ীভাবে অ্যানিমেটেড করে পরিবর্তিত করে: NO (যাতে তারা সমলয়ভাবে সম্পন্ন হয়) এবং এটি ক্র্যাশটি মুছে ফেলার পরে দেখতে পারে। এটি যদি সত্যিই আপনার সমস্যা এবং আপনি অ্যানিমেশনটি আবার চালু করতে চান তবে সঠিক কৌশলটি UINavigationControllerDellegate প্রোটোকলটি বাস্তবায়ন করা। এটি নিচের পদ্ধতিটি অন্তর্ভুক্ত করে, যা অ্যানিমেশনের পরে বলা হয়:

navigationController:didShowViewController:animated:

মূলত আপনি এই পদ্ধতিতে প্রয়োজনীয় কিছু কোড সরাতে চান যাতে অ্যানিমেশনটি শেষ না হওয়া পর্যন্ত নেভিগেশান কন্ট্রোলার স্ট্যাকে কোনও পরিবর্তন ঘটে এবং কোন স্ট্যাকগুলি আরও পরিবর্তনের জন্য প্রস্তুত হয় তা নিশ্চিত করার জন্য কোনও পদক্ষেপ না।


এই বাগটি পুনরুত্পাদন করতে, একই সময়ে দুটি ভিউ কন্ট্রোলারকে ধাক্কা দেওয়ার চেষ্টা করুন। অথবা ধাক্কা এবং একই পপিং। উদাহরণ:

আমি এমন একটি বিভাগ তৈরি করেছি যা এই কলগুলিকে আটকায় এবং নিশ্চিত করে যে সেগুলি কোনও অগ্রগতি চলাকালীন অন্য কোনও সংঘর্ষ ঘটছে না তা নিশ্চিত করে সেগুলি সুরক্ষিত করে। শুধু আপনার প্রকল্পের মধ্যে কোড অনুলিপি এবং পদ্ধতি swizzling কারণে আপনি যেতে ভাল হবে।

#import "UINavigationController+Consistent.h"
#import <objc/runtime.h>
/// This char is used to add storage for the isPushingViewController property.
static char const * const ObjectTagKey = "ObjectTag";

@interface UINavigationController ()
@property (readwrite,getter = isViewTransitionInProgress) BOOL viewTransitionInProgress;

@end

@implementation UINavigationController (Consistent)

- (void)setViewTransitionInProgress:(BOOL)property {
    NSNumber *number = [NSNumber numberWithBool:property];
    objc_setAssociatedObject(self, ObjectTagKey, number , OBJC_ASSOCIATION_RETAIN);
}


- (BOOL)isViewTransitionInProgress {
    NSNumber *number = objc_getAssociatedObject(self, ObjectTagKey);

    return [number boolValue];
}


#pragma mark - Intercept Pop, Push, PopToRootVC
/// @name Intercept Pop, Push, PopToRootVC

- (NSArray *)safePopToRootViewControllerAnimated:(BOOL)animated {
    if (self.viewTransitionInProgress) return nil;
    if (animated) {
        self.viewTransitionInProgress = YES;
    }
    //-- This is not a recursion, due to method swizzling the call below calls the original  method.
    return [self safePopToRootViewControllerAnimated:animated];

}


- (NSArray *)safePopToViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if (self.viewTransitionInProgress) return nil;
    if (animated) {
        self.viewTransitionInProgress = YES;
    }
    //-- This is not a recursion, due to method swizzling the call below calls the original  method.
    return [self safePopToViewController:viewController animated:animated];
}


- (UIViewController *)safePopViewControllerAnimated:(BOOL)animated {
    if (self.viewTransitionInProgress) return nil;
    if (animated) {
        self.viewTransitionInProgress = YES;
    }
    //-- This is not a recursion, due to method swizzling the call below calls the original  method.
    return [self safePopViewControllerAnimated:animated];
}



- (void)safePushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    self.delegate = self;
    //-- If we are already pushing a view controller, we dont push another one.
    if (self.isViewTransitionInProgress == NO) {
        //-- This is not a recursion, due to method swizzling the call below calls the original  method.
        [self safePushViewController:viewController animated:animated];
        if (animated) {
            self.viewTransitionInProgress = YES;
        }
    }
}


// This is confirmed to be App Store safe.
// If you feel uncomfortable to use Private API, you could also use the delegate method navigationController:didShowViewController:animated:.
- (void)safeDidShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    //-- This is not a recursion. Due to method swizzling this is calling the original method.
    [self safeDidShowViewController:viewController animated:animated];
    self.viewTransitionInProgress = NO;
}


// If the user doesnt complete the swipe-to-go-back gesture, we need to intercept it and set the flag to NO again.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    id<UIViewControllerTransitionCoordinator> tc = navigationController.topViewController.transitionCoordinator;
    [tc notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        self.viewTransitionInProgress = NO;
        //--Reenable swipe back gesture.
        self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController;
        [self.interactivePopGestureRecognizer setEnabled:YES];
    }];
    //-- Method swizzling wont work in the case of a delegate so:
    //-- forward this method to the original delegate if there is one different than ourselves.
    if (navigationController.delegate != self) {
        [navigationController.delegate navigationController:navigationController
                                     willShowViewController:viewController
                                                   animated:animated];
    }
}


+ (void)load {
    //-- Exchange the original implementation with our custom one.
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(pushViewController:animated:)), class_getInstanceMethod(self, @selector(safePushViewController:animated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(didShowViewController:animated:)), class_getInstanceMethod(self, @selector(safeDidShowViewController:animated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(popViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopViewControllerAnimated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToRootViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopToRootViewControllerAnimated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToViewController:animated:)), class_getInstanceMethod(self, @selector(safePopToViewController:animated:)));
}

@end

একটি ভিউ এটি একটি সাবউইউ হিসাবে যোগ করা যাবে না।

মতামতগুলি পিতামাতার-সন্তানের অনুক্রমকে বজায় রাখে, তাই যদি আপনি নিজের মধ্যে একটি সাবউইউ হিসাবে একটি দৃশ্য যোগ করেন তবে এটি ব্যতিক্রমের মাধ্যমে হবে।

যদি একটি শ্রেণি UIViewController হয় তবে তার ভিউ পেতে আপনি self.view ব্যবহার করেন।

যদি একটি ক্লাস UIView ক্লাস হয় তবে তার ভিউ পেতে আপনি স্ব ব্যবহার করুন।


পার্টি জন্য দেরী হচ্ছে জন্য দুঃখিত। আমি সম্প্রতি এই সমস্যাটি ছিলাম যেখানে আমার ন্যাভিগেশন বার একই সময়ে একাধিক ভিউ কন্ট্রোলার ধাক্কা দেওয়ার কারণে দূষিত অবস্থায় গিয়েছিল। এটি ঘটে কারণ প্রথম দৃশ্য নিয়ামক এখনও অ্যানিমেশন করার সময় অন্য দৃশ্য নিয়ামক ধাক্কা দেওয়া হয়। অপ্রতিরোধ্য উত্তর থেকে ইঙ্গিত গ্রহণ আমি আমার ক্ষেত্রে কাজ করে যা আমার সহজ সমাধান সঙ্গে এসেছিলেন। আপনি কেবল UINavigationController এবং pushViewController পদ্ধতিকে ওভাররাইড করতে হবে এবং পূর্বের ভিউ কন্ট্রোলার অ্যানিমেশনটি শেষ হয়ে গেছে কিনা তা পরীক্ষা করুন। আপনি আপনার ক্লাসকে UINavigationControllerDelegate প্রতিনিধির দ্বারা এবং UINavigationControllerDelegate প্রতিনিধিকে সেট করে অ্যানিমেশন সমাপ্তির কথা শুনতে পারেন।

আমি কিছু সহজ করতে here একটি Gist আপলোড করেছেন।

আপনার স্টোরিবোর্ডে ন্যাভিগেশন কন্ট্রোলার হিসাবে এই নতুন শ্রেণিকে সেট করেই নিশ্চিত করুন।


শুধু পাশাপাশি এই সমস্যা অভিজ্ঞ। আমাকে তোমার কোড দেখাতে দাও

override func viewDidLoad() { 
  super.viewDidLoad()

  //First, I create a UIView
  let firstFrame = CGRect(x: 50, y: 70, height: 200, width: 200)
  let firstView = UIView(frame: firstFrame)
  firstView.addBackgroundColor = UIColor.yellow
  view.addSubview(firstView) 

  //Now, I want to add a subview inside firstView
  let secondFrame = CGRect(x: 20, y:50, height: 15, width: 35)
  let secondView = UIView(frame: secondFrame)
  secondView.addBackgroundColor = UIColor.green
  firstView.addSubView(firstView)
 }

ত্রুটি এই লাইনের কারণে আসে:

firstView.addSubView(firstView)

আপনি সাবউইউ নিজেকে যোগ করতে পারবেন না। আমি কোড লাইন পরিবর্তন:

firstView.addSubView(secondView)

ত্রুটি চলে গেছে এবং আমি উভয় মতামত দেখতে সক্ষম ছিল। শুধু এই একটি উদাহরণ দেখতে চেয়েছিলেন যে কেউ সাহায্য করবে।