.NET에서 이상한 동작이 발생 presentViewController:animated:completion
합니다. 제가 만드는 것은 본질적으로 추측 게임입니다.
나는이 UIViewController
(frequencyViewController)를 포함하는 UITableView
(frequencyTableView을). 사용자가 정답이 포함 된 questionTableView의 행을 탭하면 뷰 (correctViewController)가 인스턴스화되고 해당 뷰가 모달 뷰로 화면 하단에서 위로 이동해야합니다. 이것은 사용자에게 정답이 있음을 알리고 다음 질문에 대한 준비가 된 frequencyViewController를 재설정합니다. 다음 질문을 표시하기 위해 버튼을 누를 때 correctViewController가 닫힙니다.
이 모든 것은 매번 올바르게 작동하며 올바른 ViewController의 뷰 presentViewController:animated:completion
는 animated:NO
.
내가 설정 animated:YES
하면 correctViewController가 초기화되고 viewDidLoad
. 그러나 viewWillAppear
, viewDidAppear
및의 완료 블록은 presentViewController:animated:completion
호출되지 않습니다. 두 번째 탭을 할 때까지 앱은 여전히 frequencyViewController를 표시하고 있습니다. 이제 viewWillAppear, viewDidAppear 및 완료 블록이 호출됩니다.
나는 조금 더 조사했고, 그것이 계속되게하는 것은 단지 또 다른 탭이 아니다. iPhone을 기울이거나 흔들면 viewWillLoad 등을 트리거 할 수도 있습니다. 진행되기 전에 다른 사용자 입력을 기다리는 것과 같습니다. 이것은 실제 iPhone과 시뮬레이터에서 발생하며, 진동 명령을 시뮬레이터에 전송하여 증명했습니다.
이 문제에 대해 어떻게해야할지 모르겠습니다. 누구든지 도와 줄 수있는 어떤 도움이라도 정말 감사하겠습니다.
감사
여기 내 코드가 있습니다. 아주 간단합니다 …
이것은 questionTableView에 대한 대리자 역할을하는 questionViewController의 코드입니다.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
{
// If guess was wrong, then mark the selection as incorrect
NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];
}
else
{
// If guess was correct, show correct view
NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
self.correctViewController = [[HFBCorrectViewController alloc] init];
self.correctViewController.delegate = self;
[self presentViewController:self.correctViewController animated:YES completion:^(void){
NSLog(@"Completed Presenting correctViewController");
[self setUpViewForNextQuestion];
}];
}
}
이것은 correctViewController의 전체입니다.
@implementation HFBCorrectViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
NSLog(@"[HFBCorrectViewController initWithNibName:bundle:]");
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(@"[HFBCorrectViewController viewDidLoad]");
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"[HFBCorrectViewController viewDidAppear]");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)close:(id)sender
{
NSLog(@"[HFBCorrectViewController close:sender:]");
[self.delegate didDismissCorrectViewController];
}
@end
편집하다:
이전에이 질문을 찾았습니다. UITableView 및 presentViewController가 표시하는 데 2 번의 클릭이 필요합니다.
제 didSelectRow
코드를 이것으로 변경하면 애니메이션과 함께 매우 시간이 걸립니다. 그러나 그것은 지저분하고 왜 처음부터 작동하지 않는지 이해가되지 않습니다. 그래서 저는 그것을 대답으로 간주하지 않습니다 …
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
{
// If guess was wrong, then mark the selection as incorrect
NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];
// [cell setAccessoryType:(UITableViewCellAccessoryType)]
}
else
{
// If guess was correct, show correct view
NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
////////////////////////////
// BELOW HERE ARE THE CHANGES
[self performSelector:@selector(showCorrectViewController:) withObject:nil afterDelay:0];
}
}
-(void)showCorrectViewController:(id)sender
{
self.correctViewController = [[HFBCorrectViewController alloc] init];
self.correctViewController.delegate = self;
self.correctViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:self.correctViewController animated:YES completion:^(void){
NSLog(@"Completed Presenting correctViewController");
[self setUpViewForNextQuestion];
}];
}
답변
오늘도 같은 문제가 발생했습니다. 나는 주제를 파헤 쳤고 그것이 주된 런 루프가 잠든 것과 관련이있는 것 같다.
실제로는 매우 미묘한 버그입니다. 왜냐하면 코드에 피드백 애니메이션, 타이머 등이 조금이라도 있다면 런 루프가 이러한 소스에 의해 유지되기 때문에이 문제가 드러나지 않기 때문입니다. 나는 사용하여 문제를 발견 한 UITableViewCell
그 있던 selectionStyle
으로 설정을 UITableViewCellSelectionStyleNone
더 선택 애니메이션 행 선택 핸들러 실행 된 후 runloop을 유발하지 그래서.
이를 고치기 위해 (Apple이 뭔가를 할 때까지) 몇 가지 방법으로 메인 런 루프를 트리거 할 수 있습니다.
가장 방해가되지 않는 해결책은 다음을 호출하는 것입니다 CFRunLoopWakeUp
.
[self presentViewController:vc animated:YES completion:nil];
CFRunLoopWakeUp(CFRunLoopGetCurrent());
또는 빈 블록을 기본 대기열에 넣을 수 있습니다.
[self presentViewController:vc animated:YES completion:nil];
dispatch_async(dispatch_get_main_queue(), ^{});
재미 있긴하지만 장치를 흔들면 메인 루프도 트리거됩니다 (동작 이벤트를 처리해야 함). 탭도 마찬가지지만 원래 질문에 포함되어 있습니다. 🙂 또한 시스템이 상태 표시 줄을 업데이트하면 (예 : 시계 업데이트, WiFi 신호 강도 변경 등) 메인 루프를 깨우고보기를 표시합니다. 제어 장치.
관심있는 사람을 위해 나는 runloop 가설을 확인하기 위해 문제에 대한 최소한의 데모 프로젝트를 작성했습니다 : https://github.com/tzahola/present-bug
또한 Apple에 버그를보고했습니다.
답변
이것을 확인하십시오 : https://devforums.apple.com/thread/201431
모든 것을 읽고 싶지 않다면-일부 사람들 (나를 포함하여)을위한 해결책 presentViewController
은 주 스레드에서 명시 적으로 호출 하는 것입니다 .
Swift 4.2 :
DispatchQueue.main.async {
self.present(myVC, animated: true, completion: nil)
}
목표 -C :
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:myVC animated:YES completion:nil];
});
아마도 iOS7은 didSelectRowAtIndexPath
.
답변
다음 코드를 사용하여 Swift 3.0에서 우회했습니다.
DispatchQueue.main.async {
self.present(UIViewController(), animated: true, completion: nil)
}
답변
[viewController view]
표시되는 뷰 컨트롤러를 호출 하면 트릭이 생겼습니다.
답변
무엇을하는지 궁금합니다 [self setUpViewForNextQuestion];
.
[self.correctViewController.view setNeedsDisplay];
에서 완료 블록의 끝에서 호출 을 시도 할 수 presentViewController
있습니다.
답변
문제를 해결하는 UIViewController에 대한 방법을 사용하여 확장 (카테고리)을 작성했습니다. 구현 힌트 ( swift / objective-c )에 대한 AX 및 NSHipster에게 감사드립니다 .
빠른
extension UIViewController {
override public class func initialize() {
struct DispatchToken {
static var token: dispatch_once_t = 0
}
if self != UIViewController.self {
return
}
dispatch_once(&DispatchToken.token) {
let originalSelector = Selector("presentViewController:animated:completion:")
let swizzledSelector = Selector("wrappedPresentViewController:animated:completion:")
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
}
else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
}
func wrappedPresentViewController(viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
dispatch_async(dispatch_get_main_queue()) {
self.wrappedPresentViewController(viewControllerToPresent, animated: flag, completion: completion)
}
}
}
목표 -C
#import <objc/runtime.h>
@implementation UIViewController (Swizzling)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(presentViewController:animated:completion:);
SEL swizzledSelector = @selector(wrappedPresentViewController:animated:completion:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
- (void)wrappedPresentViewController:(UIViewController *)viewControllerToPresent
animated:(BOOL)flag
completion:(void (^ __nullable)(void))completion {
dispatch_async(dispatch_get_main_queue(),^{
[self wrappedPresentViewController:viewControllerToPresent
animated:flag
completion:completion];
});
}
@end
답변
스토리 보드의 셀에 Selection = none인지 확인
그렇다면 파란색 또는 회색으로 변경하면 작동합니다.