พยายามแสดง UIViewController บน UIViewController ซึ่งมุมมองไม่ได้อยู่ในลำดับชั้นของหน้าต่าง


599

เพิ่งเริ่มใช้ Xcode 4.5 และฉันได้รับข้อผิดพลาดนี้ในคอนโซล:

คำเตือน: พยายามแสดง <finishViewController: 0x1e56e0a0> บน <ViewController: 0x1ec3e000> ซึ่งมุมมองไม่ได้อยู่ในลำดับชั้นของหน้าต่าง!

มุมมองยังคงถูกนำเสนอและทุกอย่างในแอปทำงานได้ดี นี่เป็นสิ่งใหม่ใน iOS 6 หรือไม่

นี่คือรหัสที่ฉันใช้เพื่อเปลี่ยนระหว่างมุมมอง:

UIStoryboard *storyboard = self.storyboard;
finishViewController *finished = 
[storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];

[self presentViewController:finished animated:NO completion:NULL];

3
ฉันมีปัญหาเดียวกันแน่นอนยกเว้นพยายามโทรหาpresentViewController:animated:completionตัวควบคุม nav คุณทำสิ่งนี้ในตัวแทนแอพหรือไม่
tarnfeld

ไม่ฉันกำลังทำจากตัวควบคุมมุมมองหนึ่งไปอีกตัวหนึ่ง คุณพบวิธีแก้ไขปัญหาหรือไม่?
Kyle Goslan

ปัญหาเดียวกันในส่วนของรหัสที่ใช้งานได้เสมอก่อนที่จะใช้ Xcode 4.5 ฉันกำลังนำเสนอ UINavigationController แต่ก็ใช้งานได้อีกครั้งก่อนหน้านี้
Emanuele Fumagalli

ฉันมีปัญหาเดียวกันไม่ได้รับการแก้ไข ทำจากผู้แทนแอปและ rootviewcontroller เรียกว่า "presentViewController" โดยใช้ UITabBarController
darksider

3
นอกจากนี้หากเรียกวิธีนี้ก่อนโทร makeKeyAndVisible ให้ย้ายหลังจากนั้น
mike_haney

คำตอบ:


1296

คุณเรียกวิธีนี้จากที่ไหน ฉันมีปัญหาที่ฉันพยายามนำเสนอตัวควบคุมมุมมอง modal ภายในviewDidLoadวิธีการ ทางออกสำหรับฉันคือการย้ายสายนี้ไปที่viewDidAppear:วิธีการ

ข้อสันนิษฐานของฉันคือว่ามุมมองของตัวควบคุมมุมมองไม่ได้อยู่ในลำดับชั้นของมุมมองหน้าต่าง ณ จุดที่มันถูกโหลด (เมื่อviewDidLoadข้อความถูกส่ง) แต่มันอยู่ในลำดับชั้นของหน้าต่างหลังจากที่มันถูกนำเสนอ (เมื่อviewDidAppear:ข้อความถูกส่ง) .


ความระมัดระวัง

หากคุณโทรไปpresentViewController:animated:completion:ที่viewDidAppear:คุณอาจพบปัญหาโดยที่ตัวควบคุมมุมมอง modal จะถูกนำเสนออยู่เสมอเมื่อใดก็ตามที่มุมมองของตัวควบคุมมุมมองปรากฏขึ้น .

บางทีนี่อาจไม่ใช่สถานที่ที่ดีที่สุดในการนำเสนอตัวควบคุมมุมมอง modal หรืออาจต้องมีการเพิ่มเติมสถานะบางอย่างซึ่งช่วยให้ตัวควบคุมมุมมองการนำเสนอเพื่อตัดสินใจว่าควรแสดงตัวควบคุมมุมมอง modal ทันทีหรือไม่


6
@James คุณถูกต้องมุมมองไม่ได้อยู่ในลำดับชั้นจนกระทั่งหลังจาก viewWillAppear ได้รับการแก้ไขและเมื่อ viewDidAppear ถูกเรียก ถ้านี่เป็นคำถามของฉันฉันจะยอมรับคำตอบนี้;)
แมตต์ Mc

6
@ เจมส์ขอบคุณ การใช้ ViewDidAppear แก้ปัญหาให้ฉันด้วย มีเหตุผล.
อาลี

44
ฉันหวังว่าฉันจะลงคะแนนได้สองครั้ง ฉันเพิ่งมีปัญหานี้และมาที่หัวข้อเพื่อค้นหาว่าฉัน upvoted แล้วครั้งล่าสุดที่ฉันเห็นสิ่งนี้
Schrockwell

7
โปรดทราบว่าเมื่อคุณเปลี่ยน VC ใน viewDidAppear สิ่งนี้จะทำให้การดำเนินการของ segue ด้วย Animation ทำให้แฟลช / จอแสดงผลของพื้นหลัง
Vincent

2
ใช่เคล็ดลับคือภาพเคลื่อนไหว WillAppear: (BOOL) เนื่องจากถูกต้อง สิ่งสำคัญอีกอย่างหนึ่งที่คุณต้องเรียกว่า super ในวิธีนี้คือ [super viewDidAppear: animated]; มันจะไม่ทำงาน
BootMaker

66

อีกสาเหตุที่เป็นไปได้:

ฉันมีปัญหานี้เมื่อฉันนำเสนอตัวควบคุมมุมมองเดียวกันสองครั้งโดยไม่ได้ตั้งใจ (ครั้งหนึ่งperformSegueWithIdentifer:sender:ซึ่งถูกเรียกเมื่อกดปุ่มและเป็นครั้งที่สองที่มีส่วนต่อเชื่อมต่อโดยตรงกับปุ่ม)

อย่างมีประสิทธิภาพสองส่วนย่อยถูกยิงพร้อมกันและฉันได้รับข้อผิดพลาด: Attempt to present X on Y whose view is not in the window hierarchy!


4
ฉันมีข้อผิดพลาดเหมือนกันและคำตอบของคุณที่นี่ช่วยให้ฉันทราบว่าเกิดอะไรขึ้นจริง ๆ แล้วมันเป็นข้อผิดพลาดนี้แก้ไขได้เพราะคุณขอบคุณขอบคุณ +1
samouray

1
ฉันลบส่วนต่อท้ายเก่าและเชื่อมต่อ VC กับ VC มีวิธีการเชื่อมต่อปุ่มเข้ากับกระดานเรื่องราวกับ VC เพราะวิธีนั้นทำให้ฉันมีข้อผิดพลาดอยู่เรื่อย ๆ ?
MCB

ฉันมีข้อผิดพลาดเดียวกันคำตอบของคุณแก้ไขปัญหาของฉันขอบคุณสำหรับความสนใจของคุณ ขอแสดงความนับถือ.
iamburak

1
ฮ่า ๆ บังเอิญฉันยังสร้าง vc สองตัว: จากปุ่มและดำเนินการส่วนขอบคุณสำหรับเคล็ดลับ !!!
Borzh

1
ในกรณีของฉันฉันโทรpresent(viewController, animated: true, completion: nil)ภายในวง
ซามัว

38

viewWillLayoutSubviewsและviewDidLayoutSubviews(iOS 5.0+) สามารถใช้เพื่อจุดประสงค์นี้ พวกเขาถูกเรียกว่าเร็วกว่า viewDidAppear


3
พวกเขายังคงใช้ในโอกาสอื่น ๆ ดังนั้นฉันคิดว่าพวกเขาอาจถูกเรียกหลายครั้งใน "อายุการใช้งาน" ของมุมมอง
Jonny

มันก็ไม่ได้เป็นวิธีการ - ตามชื่อแนะนำ viewDidAppear ถูกต้อง การอ่านเกี่ยวกับวงจรชีวิตของมุมมองเป็นความคิดที่ดี
tooluser

นี่คือทางออกที่ดีที่สุด ในกรณีของฉันการนำเสนอใน viewDidAppear ทำให้การแสดงตัวแยกที่สองของตัวควบคุมมุมมองก่อนที่จะโหลด modal ซึ่งไม่สามารถยอมรับได้
TMilligan

คำตอบนี้ทำงานได้ดีที่สุดสำหรับฉันเมื่อพยายามแสดงการแจ้งเตือน การแจ้งเตือนจะไม่แสดงเมื่อฉันใส่ไว้ใน viewDidLoad และ viewWillAppear
uplearnedu.com

26

สำหรับแสดงมุมมองย่อยไปยังมุมมองหลักโปรดใช้รหัสต่อไปนี้

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];

สำหรับการปิดมุมมองย่อยใด ๆ จากมุมมองหลักโปรดใช้รหัสต่อไปนี้

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];

ทำงานให้ฉันด้วย
Aziz Javed

17

ฉันยังพบปัญหานี้เมื่อฉันพยายามที่จะนำเสนอในUIViewController viewDidLoadคำตอบของ James Bedford ทำงานได้ แต่แอปของฉันแสดงพื้นหลังเป็นครั้งแรกเป็นเวลา 1 หรือ 2 วินาที

addChildViewControllerหลังจากการวิจัยบางอย่างที่ฉันได้พบวิธีที่จะแก้ปัญหานี้โดยใช้การ

- (void)viewDidLoad
{
    ...
    [self.view addSubview: navigationViewController.view];
    [self addChildViewController: navigationViewController];
    ...
}

9
ฉันคิดว่าคุณหายไป [navigationViewController didMoveToParentViewController: self]
foFox

2
ฉันลองใช้รหัสของคุณพร้อมกับข้อเสนอแนะของ foFox และเมื่อฉันไปลบมันออกจากแม่มันจะไม่หายไป lololol ยังคงติดอยู่กับที่ไม่มีการแก้ไข
Logicsaurus Rex

ทำงานใน Swift3.1
Kang Byul

@sunkehappy เหนือสองบรรทัดที่จะใช้ในก่อนหน้าปัจจุบันผู้ควบคุม แต่มันล้มเหลวทำไม?
Iyyappan Ravi

14

อาจจะเป็นเช่นฉันคุณมีรากผิด viewController

ฉันต้องการที่จะแสดงViewControllerในnon-UIViewControllerบริบท

ดังนั้นฉันไม่สามารถใช้รหัสดังกล่าว:

[self presentViewController:]

ดังนั้นฉันได้รับ UIViewController:

[[[[UIApplication sharedApplication] delegate] window] rootViewController]

ด้วยเหตุผลบางอย่าง (ข้อผิดพลาดเชิงตรรกะ) rootViewControllerสิ่งที่นอกเหนือจากที่คาดไว้ (ปกติUIViewController) จากนั้นฉันแก้ไขข้อผิดพลาดแทนที่rootViewControllerด้วย a UINavigationControllerและปัญหาหายไป


8

TL; DRคุณสามารถมี 1 rootViewController เท่านั้นและมีการนำเสนอล่าสุด ดังนั้นอย่าพยายามให้ผู้ควบคุมการชมเสนอตัวควบคุมการดูอีกคนหนึ่งเมื่อมีการนำเสนอตัวควบคุมที่ไม่ได้ถูกไล่ออกไปแล้ว

หลังจากทำการทดสอบของฉันเองฉันก็ได้ข้อสรุป

หากคุณมี rootViewController ที่คุณต้องการนำเสนอทุกอย่างคุณสามารถพบปัญหานี้ได้

นี่คือรหัส rootController ของฉัน (เปิดเป็นทางลัดของฉันสำหรับการนำเสนอ viewcontroller จากรูท)

func open(controller:UIViewController)
{
    if (Context.ROOTWINDOW.rootViewController == nil)
    {
        Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
        Context.ROOTWINDOW.makeKeyAndVisible()
    }

    ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}

ถ้าฉันโทรเปิดสองครั้งในแถว (ไม่คำนึงถึงเวลาที่ผ่านไป) สิ่งนี้จะใช้ได้ดีเมื่อเปิดครั้งแรก แต่ไม่เปิดครั้งที่สอง การเปิดครั้งที่สองจะส่งผลให้เกิดข้อผิดพลาดด้านบน

อย่างไรก็ตามถ้าฉันปิดมุมมองที่นำเสนอล่าสุดจากนั้นเปิดการโทรมันจะทำงานได้ดีเมื่อฉันเรียกเปิดอีกครั้ง (บนตัวควบคุมมุมมองอื่น)

func close(controller:UIViewController)
{
    ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}

สิ่งที่ฉันสรุปไว้คือ rootViewController ของ MOST-RECENT-CALL เท่านั้นที่อยู่ในมุมมองลำดับชั้น (แม้ว่าคุณจะไม่ได้ยกเลิกหรือลบมุมมองก็ตาม) ฉันลองเล่นกับการเรียกโหลดเดอร์ทั้งหมด (viewDidLoad, viewDidAppear และทำการโทรส่งแบบหน่วงเวลา) และฉันพบว่าวิธีเดียวที่ฉันสามารถทำให้มันทำงานได้คือการเรียกปัจจุบันจากตัวควบคุมมุมมองด้านบนสุดเท่านั้น


ดูเหมือนว่าจะเป็นปัญหาที่พบบ่อยมากที่คำตอบมากมายที่โหวตให้คุณ โชคร้ายนี่เป็นประโยชน์อย่างมาก
rayepps

ใช่ทุกอย่างดีและดี แต่สิ่งที่เป็นทางออก ... ฉันมีด้ายคนงานพื้นหลังไปที่เซิร์ฟเวอร์และการแสดงสตอรี่บอร์ดซ้ายขวาและศูนย์และวิธีการทั้งหมดเป็นของปลอม .. มันน่ากลัว .. สิ่งที่ควรเป็นสายลมอย่างเต็มที่ เรื่องตลกเพราะฉันต้องการทำ int เขาด้ายพื้นหลังคือ: wait wait decide push screen to frontและมันเป็นไปไม่ได้ที่เป็น IOS ????
Mr Heelis

5

ปัญหาของฉันคือผมได้ดำเนินการทำต่อในUIApplicationDelegate's didFinishLaunchingWithOptionsวิธีการก่อนที่ผมจะเรียกว่าmakeKeyAndVisible()ที่หน้าต่าง


อย่างไร คุณสามารถทำอย่างละเอียด? ฉันกำลังเผชิญกับปัญหาเดียวกัน นี้เป็นรหัสของฉันให้ initialViewControlleripad: UIViewController = mainStoryboardIpad.instantiateViewController (withIdentifier: "SplashController") ในฐานะ UIViewController self.window .rootViewController = initialViewControlleripad self.window .makeKeyAndVisible ()??
shahtaj khalid

4

ในสถานการณ์ของฉันฉันไม่สามารถวางระเบิดในชั้นเรียนได้ ดังนั้นนี่คือสิ่งที่ฉันได้รับ:

let viewController = self // I had viewController passed in as a function,
                          // but otherwise you can do this


// Present the view controller
let currentViewController = UIApplication.shared.keyWindow?.rootViewController
currentViewController?.dismiss(animated: true, completion: nil)

if viewController.presentedViewController == nil {
    currentViewController?.present(alert, animated: true, completion: nil)
} else {
    viewController.present(alert, animated: true, completion: nil)
}

3

ผมมีปัญหาเดียวกัน. ฉันต้องฝังตัวควบคุมการนำทางและนำเสนอตัวควบคุมผ่านทางนั้น ด้านล่างนี้คือตัวอย่างรหัส

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIImagePickerController *cameraView = [[UIImagePickerController alloc]init];
    [cameraView setSourceType:UIImagePickerControllerSourceTypeCamera];
    [cameraView setShowsCameraControls:NO];

    UIView *cameraOverlay = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 768, 1024)];
    UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"someImage"]];
    [imageView setFrame:CGRectMake(0, 0, 768, 1024)];
    [cameraOverlay addSubview:imageView];

    [cameraView setCameraOverlayView:imageView];

    [self.navigationController presentViewController:cameraView animated:NO completion:nil];
//    [self presentViewController:cameraView animated:NO completion:nil]; //this will cause view is not in the window hierarchy error

}

3

หากคุณมีวัตถุ AVPlayer พร้อมวิดีโอที่เล่นคุณต้องหยุดวิดีโอก่อน


ฉันหมายความว่าวิดีโอควรหยุด / หยุดชั่วคราวก่อน
Vlad

จริงนี้ช่วยให้ผมมันทำให้ผมหลังจากนี้stackoverflow.com/questions/20746413/...
โอมาร์ N Shamali

3

ฉันมีปัญหาเดียวกัน ปัญหาคือ, performSegueWithIdentifier ถูกทริกเกอร์โดยการแจ้งเตือนทันทีที่ฉันวางการแจ้งเตือนบนเธรดหลักข้อความเตือนจะหายไป



3

ในกรณีที่ช่วยใครได้ปัญหาของฉันมันช่างแสนงี่เง่า ความผิดทั้งหมดของฉันแน่นอน การแจ้งเตือนกำลังเรียกวิธีการที่เรียกโมดอล แต่ฉันไม่ได้ลบการแจ้งเตือนอย่างถูกต้องดังนั้นในบางครั้งฉันอาจมีการแจ้งเตือนมากกว่าหนึ่งครั้งดังนั้นคำกริยาจะได้รับการเรียกหลายครั้ง แน่นอนว่าหลังจากที่คุณเรียกโมดอลหนึ่งครั้งวิวเวอร์คอนโทรลเลอร์ที่เรียกมันว่ามันไม่ได้อยู่ในลำดับชั้นการดูอีกต่อไปนั่นคือสาเหตุที่เราเห็นปัญหานี้ สถานการณ์ของฉันทำให้เกิดปัญหาอื่นอีกเช่นกันตามที่คุณคาดหวัง

ดังนั้นเพื่อสรุปสิ่งที่คุณกำลังทำอยู่ให้แน่ใจว่ากิริยาที่ไม่ได้ถูกเรียกว่ามากกว่าหนึ่งครั้ง


3

ฉันลงเอยด้วยรหัสที่ใช้งานได้ในที่สุด (Swift) โดยพิจารณาว่าคุณต้องการแสดงผลviewControllerจากที่ใดก็ได้ รหัสนี้จะผิดพลาดอย่างเห็นได้ชัดเมื่อไม่มี rootViewController นั่นคือจุดสิ้นสุดที่เปิดอยู่ นอกจากนี้ยังไม่รวมถึงการสลับไปใช้เธรด UI ที่ต้องการ

dispatch_sync(dispatch_get_main_queue(), {
    guard !NSBundle.mainBundle().bundlePath.hasSuffix(".appex") else {
       return; // skip operation when embedded to App Extension
    }

    if let delegate = UIApplication.sharedApplication().delegate {
        delegate.window!!.rootViewController?.presentViewController(viewController, animated: true, completion: { () -> Void in
            // optional completion code
        })
    }
}

BTW เพื่อทำความเข้าใจฉันจะเรียกวิธีการนี้จากที่ใด ... เป็นห้องสมุด SDK แบบ UI ที่น้อยกว่าซึ่งแสดง UI ของตัวเองเหนือแอปของคุณในบางกรณี (ไม่เปิดเผย)
igraczech

คุณจะหยุดทำงานและเบิร์นหากมีคนตัดสินใจฝัง sdk ของคุณในแอปที่มีส่วนขยาย ผ่าน UIViewController ไปยังการละเมิดวิธี sdk init ของคุณ [s]
Anton Tropashko

คุณแอนตันจริง รหัสนี้เขียนเมื่อไม่มีส่วนขยายและ SDK ยังไม่ได้ใช้ในส่วนใด ๆ ฉันได้เพิ่มส่วนป้องกันเพื่อข้ามตัวพิมพ์ขอบนี้
igraczech

3

คำเตือนประเภทนี้อาจหมายถึงคุณกำลังพยายามนำเสนอสิ่งใหม่ ๆView Controllerผ่านNavigation Controllerขณะที่สิ่งนี้Navigation ControllerกำลังนำเสนออีกView Controllerครั้ง ในการแก้ไขคุณจะต้องยกเลิกการนำเสนอView Controllerในตอนแรกและเมื่อเสร็จแล้วให้นำเสนอใหม่ สาเหตุของการเตือนอีกสามารถพยายามที่จะนำเสนอในหัวข้ออื่นมากกว่าView Controllermain


3

ฉันมีปัญหาที่คล้ายกันในSwift 4.2แต่มุมมองของฉันไม่ได้ถูกนำเสนอจากรอบการดู ฉันพบว่าฉันมีการนำเสนอหลายชุดพร้อมกันในเวลาเดียวกัน ดังนั้นฉันใช้ dispatchAsyncAfter

func updateView() {

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in

// for programmatically presenting view controller 
// present(viewController, animated: true, completion: nil)

//For Story board segue. you will also have to setup prepare segue for this to work. 
 self?.performSegue(withIdentifier: "Identifier", sender: nil)
  }
}

2

ฉันแก้ไขมันโดยการย้ายstart()ฟังก์ชั่นภายในdismissบล็อคความสมบูรณ์:

self.tabBarController.dismiss(animated: false) {
  self.start()
}

เริ่มต้นประกอบด้วยการเรียกสองสายไปยังสายself.present()หนึ่งสำหรับ UINavigationController และอีกสายหนึ่งสำหรับUIImagePickerControllerและอีกคนหนึ่งสำหรับ

นั่นแก้ไขให้ฉัน


1

นอกจากนี้คุณยังสามารถรับคำเตือนนี้เมื่อดำเนินการต่อจากตัวควบคุมมุมมองที่ฝังอยู่ในภาชนะ วิธีการแก้ไขที่ถูกต้องคือใช้ segue จากพาเรนต์ของคอนเทนเนอร์ไม่ใช่จากตัวควบคุมมุมมองของคอนเทนเนอร์


1

ต้องเขียนบรรทัดด้านล่าง

self.searchController.definesPresentationContext = true

แทน

self.definesPresentationContext = true

ใน UIViewController


1

ด้วย Swift 3 ...

อีกสาเหตุที่เป็นไปได้สำหรับสิ่งนี้ซึ่งเกิดขึ้นกับฉันคือการต่อจาก tableViewCell ไปยัง ViewController อื่นบน Storyboard ฉันยังใช้override func prepare(for segue: UIStoryboardSegue, sender: Any?) {}เมื่อมีการคลิกเซลล์

ฉันแก้ไขปัญหานี้โดยการทำต่อจาก ViewController ไปยัง ViewController


1

ฉันมีปัญหานี้และสาเหตุที่แท้จริงคือการสมัครรับการคลิกปุ่มจัดการ (TouchUpInside) หลายครั้ง

มันเป็นการสมัครสมาชิกใน ViewWillAppear ซึ่งถูกเรียกหลายครั้งเนื่องจากเราได้เพิ่มการนำทางเพื่อไปยังตัวควบคุมอื่นแล้วกลับไปที่เดิม


1

มันเกิดขึ้นกับฉันว่าการเล่าเรื่องราวในกระดานเรื่องราวนั้นแตกหักบ้าง การลบส่วนย่อย (และสร้างส่วนย่อยเดิมอีกครั้ง) แก้ไขปัญหาได้


1

ด้วยหน้าต่างหลักของคุณอาจมีบางครั้งที่การเปลี่ยนแปลงที่เข้ากันไม่ได้กับการนำเสนอการแจ้งเตือน เพื่อให้สามารถนำเสนอการแจ้งเตือนได้ตลอดเวลาในรอบการสมัครของคุณคุณควรมีหน้าต่างแยกต่างหากเพื่อทำงาน

/// independant window for alerts
@interface AlertWindow: UIWindow

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message;

@end

@implementation AlertWindow

+ (AlertWindow *)sharedInstance
{
    static AlertWindow *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[AlertWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    });
    return sharedInstance;
}

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message
{
    // Using a separate window to solve "Warning: Attempt to present <UIAlertController> on <UIViewController> whose view is not in the window hierarchy!"
    UIWindow *shared = AlertWindow.sharedInstance;
    shared.userInteractionEnabled = YES;
    UIViewController *root = shared.rootViewController;
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    alert.modalInPopover = true;
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        shared.userInteractionEnabled = NO;
        [root dismissViewControllerAnimated:YES completion:nil];
    }]];
    [root presentViewController:alert animated:YES completion:nil];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    self.userInteractionEnabled = NO;
    self.windowLevel = CGFLOAT_MAX;
    self.backgroundColor = UIColor.clearColor;
    self.hidden = NO;
    self.rootViewController = UIViewController.new;

    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(bringWindowToTop:)
                                               name:UIWindowDidBecomeVisibleNotification
                                             object:nil];

    return self;
}

/// Bring AlertWindow to top when another window is being shown.
- (void)bringWindowToTop:(NSNotification *)notification {
    if (![notification.object isKindOfClass:[AlertWindow class]]) {
        self.hidden = YES;
        self.hidden = NO;
    }
}

@end

การใช้งานพื้นฐานที่โดยการออกแบบจะประสบความสำเร็จเสมอ:

[AlertWindow presentAlertWithTitle:@"My title" message:@"My message"];

1

น่าเศร้าที่วิธีแก้ปัญหาที่ยอมรับไม่ได้ผลกับคดีของฉัน ฉันพยายามนำทางไปยัง View Controller ใหม่ทันทีหลังจากคลี่คลายจาก View Controller อื่น

ฉันพบวิธีแก้ปัญหาโดยใช้การตั้งค่าสถานะเพื่อระบุว่าคลายการเรียกซีจีใด

@IBAction func unwindFromAuthenticationWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToMainTabBar = true
}

@IBAction func unwindFromForgetPasswordWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToLogin = true
}

จากนั้นนำเสนอ VC ที่ต้องการด้วย present(_ viewControllerToPresent: UIViewController)

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    if self.shouldSegueToMainTabBar {
        let mainTabBarController = storyboard.instantiateViewController(withIdentifier: "mainTabBarVC") as! MainTabBarController
        self.present(mainTabBarController, animated: true)
        self.shouldSegueToMainTabBar = false
    }
    if self.shouldSegueToLogin {
        let loginController = storyboard.instantiateViewController(withIdentifier: "loginVC") as! LogInViewController
        self.present(loginController, animated: true)
        self.shouldSegueToLogin = false
    }
}

โดยทั่วไปรหัสข้างต้นจะให้ฉันได้รับการผ่อนคลายจากการเข้าสู่ระบบ / ลงทะเบียน VC และนำทางไปยังแดชบอร์ดหรือจับการกระทำที่ผ่อนคลายจากการลืมรหัสผ่าน VC และนำทางไปยังหน้าเข้าสู่ระบบ


1

ฉันแก้ไขข้อผิดพลาดนี้ด้วยการจัดเก็บ viewcontroller ส่วนใหญ่ด้านบนเป็นค่าคงที่ซึ่งพบได้ในขณะที่วนรอบ rootViewController:

if var topController = UIApplication.shared.keyWindow?.rootViewController {
    while let presentedViewController = topController.presentedViewController {
        topController = presentedViewController
    }
    topController.present(controller, animated: false, completion: nil)
    // topController should now be your topmost view controller
}

1

ผมพบข้อผิดพลาดนี้มาถึงหลังจากการปรับปรุง Xcode ผมเชื่อว่าสวิฟท์ 5 ปัญหาเกิดขึ้นเมื่อฉันเปิดใช้งานคิวโดยตรงโดยทางโปรแกรมหลังจากคลี่คลายตัวควบคุมมุมมอง

วิธีการแก้ปัญหามาถึงในขณะที่แก้ไขข้อผิดพลาดที่เกี่ยวข้องซึ่งขณะนี้ผู้ใช้สามารถคลายการแบ่งย่อยโดยการปัดหน้าลง นี่เป็นการทำลายตรรกะของโปรแกรมของฉัน

มันได้รับการแก้ไขโดยการเปลี่ยนโหมดการนำเสนอในตัวควบคุมมุมมองทั้งหมดจากอัตโนมัติเป็นเต็มหน้าจอเต็มหน้าจอ

คุณสามารถทำได้ในแผงคุณสมบัติในตัวสร้างส่วนต่อประสาน หรือดูคำตอบนี้สำหรับวิธีการเขียนโปรแกรม


0

ฉันเพิ่งมีปัญหานี้ด้วย แต่ไม่มีอะไรเกี่ยวข้องกับเวลา ฉันใช้ซิงเกิลตันเพื่อจัดการกับฉากและฉันตั้งเป็นพรีเซนเตอร์ ในคำอื่น ๆ "ตัวเอง" ไม่ได้ติดอะไรเลย ฉันเพิ่งสร้าง "ฉาก" ภายในของมันเป็นพรีเซนเตอร์ใหม่และ voila มันทำงานได้ (Voila สูญเสียการสัมผัสหลังจากที่คุณเรียนรู้ความหมายของมัน)

ดังนั้นใช่มันไม่เกี่ยวกับ "ค้นหาทางที่ถูกต้องอย่างน่าอัศจรรย์" มันเกี่ยวกับการทำความเข้าใจว่ารหัสของคุณอยู่ที่ใดและทำอะไรอยู่ ฉันมีความสุขที่แอปเปิ้ลให้ข้อความเตือนภาษาอังกฤษแบบธรรมดาแม้จะมีความรู้สึก ความรุ่งโรจน์ของแอปเปิ้ลผู้พัฒนาที่ทำเช่นนั้น !!


0

หากโซลูชันอื่น ๆ ดูไม่ดีด้วยเหตุผลบางอย่างคุณยังคงสามารถใช้ประโยชน์workaroundจากการแสดงด้วยความล่าช้าเป็น 0 เช่นนี้:

dispatch_after(0, dispatch_get_main_queue(), ^{
    finishViewController *finished = [self.storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];
    [self presentViewController:finished animated:NO completion:NULL];    
});

ในขณะที่ฉันไม่เห็นว่ามีเอกสารรับรองใด ๆ ว่า VC ของคุณจะอยู่ในลำดับชั้นการดูในช่วงเวลาที่มีการกำหนดการบล็อกเพื่อดำเนินการ แต่ฉันสังเกตเห็นว่ามันทำงานได้ดี

การใช้ความล่าช้าเช่น 0.2 วินาทีก็เป็นตัวเลือกเช่นกัน และสิ่งที่ดีที่สุด - ด้วยวิธีนี้คุณไม่จำเป็นต้องยุ่งกับตัวแปรบูลีนviewDidAppear:


2
ขณะนี้อาจใช้งานได้ในขณะนี้ไม่มีการรับประกันว่า Apple จะเปลี่ยนพฤติกรรมและทำลายสิ่งนี้กับคุณในอนาคต จากนั้นเมื่อคุณกลับไปดูโค้ดของคุณเพื่อลองและแก้ไขสิ่งต่าง ๆ อีกครั้งคุณจะสงสัยว่าทำไมคุณถึงทำสิ่งนี้โดยไม่จำเป็น
Cruinh

การส่งด้วยเวลา 0 ช่วยฉันได้หลายครั้งแล้ว - บางครั้งสิ่งที่ควรจะมีเหตุผลก็ไม่ได้ผลหากไม่มี ดังนั้นเพียงแค่แสดงความคิดเห็นให้ตัวคุณเองและคนอื่น ๆ ว่าทำไมคุณถึงทำสิ่งที่ไม่เด่น (ไม่ใช่แค่การส่ง) และคุณควรจะปรับ
Dannie P

2
คุณเพิ่งแฮ็คปัญหาและไม่แก้ไข
Michael Peterson

0

สิ่งนี้ใช้สำหรับการนำเสนอตัวควบคุมมุมมองใด ๆ หากคุณมีตัวควบคุมการนำทางที่มีอยู่ self.navigationController? .present (MyViewController, ภาพเคลื่อนไหว: จริง, เสร็จสิ้น: ไม่มี) นอกจากนี้ฉันยังสามารถนำเสนอการแจ้งเตือนและตัวควบคุมอีเมลด้วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.