2012-07-27 4 views
0

저는 몇 달 동안 앱을 개발 해왔지만, 마침내 스스로 해결할 수없는 문제에 부딪혔습니다. 인터넷에서 도움을받을 수있는 정보가 없습니다.UIAlertView 렌더링 오류

내 앱에서 여러 개의 일반적인 UIAlertView를 사용하고 있습니다. 일부에는 2 개의 버튼이 있고, 일부에는 3 개의 버튼이 있으며, 한 개의 버튼에는 2 개의 버튼과 텍스트 필드가 있습니다. 그러나 모두 같은 문제가 있습니다. [someAlertView show]를 호출하면; 경고보기가 정상적으로 나타나지만 갑자기 화면이 보일 때 갑자기 그래픽 컨텍스트가 손상된 것처럼 보입니다.

UIAlertView Rendered incorrectly

이 모두 아이폰시오 시뮬레이터 (5.0 및 5.1 모두)에서 발생하고,뿐만 아니라 아이 패드와 아이폰 4S 단말기에서 발생한다.

통해 표시되는 이미지는 alertView 뒤에있는 것입니다.

경고가 계속 작동하고 단추를 클릭하고 텍스트 필드에 입력 한 다음 위임 할 때 메서드가 올바르게 호출되고 모든 것이 정상으로 돌아갑니다. alertView가 다시 나타나면 같은 일이 발생합니다.

경고 뒤에있는보기는 UIImage를 배경으로 약 4000 픽셀 x 1000 크기의 콘텐츠 크기를 갖는 사용자 지정 UIScrollView 하위 클래스입니다. png 파일은 대부분 투명하므로 메모리 크기가 약 80kB 밖에되지 않으며 휴대 전화에 렌더링 문제가 없습니다. 스크롤보기는 여전히 응답 성이 좋으며 속도가 느리지 않습니다. 또한 하위 클래스의 일부로 CADisplayLink 타이머가 연결되어 있습니다. alertView가 표시되기 전에이 기능을 사용하지 않으려 고 시도했지만 아무런 차이가 없으므로 문제는 아닌지 의심 스럽습니다.

이 응용 프로그램은 내가 대학 프로젝트를 위해 만든 하나의 부분을 다시 작성한 것이며 같은 크기 및 하위 클래스의 scrollView 맨 위에 아무런 문제없이 UIAlertViews를 표시 할 수 있습니다. 이 앱과 그 차이점은 이전 앱에서는 pickerView와 같은 추가 작업을 추가하기 위해 UIAlertView를 서브 클래 싱했으나 모든 것이 경고 상태에서 벗어난 것처럼 보이지 않는다고 결정했습니다. 그냥 표준 UIAlertView를 고집합니다.

이 스크린 샷에 alertView가 호출하는 방법입니다 : 이것은 scrollViews CADisplay 링크를 중지 할 수있는 기능을 추가 할 분류 AlertView 인으로

- (IBAction)loadSimulation:(id)sender { 
    importAlert = [[UIAlertView alloc] initWithTitle:@"Load Simulation" message:@"Enter Filename:" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Load", nil]; 
    [importAlert setAlertViewStyle:UIAlertViewStylePlainTextInput]; 
    [importAlert showPausingSimulation:self.simulationView]; //Calling [importAlert show]; makes no difference. 
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 
     [self hideOrganiser]; //Not an issue as the problem occurs on iPad as well. 
    } 
} 

.

@interface UIAlertView(pauseDisplayLink) 
- (void)showPausingSimulation:(UILogicSimulatorView*)simulationView; 
@end 

@implementation UIAlertView(pauseDisplayLink) 

- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView { 
    [simulationView stopRunning]; 
    [simulationView removeDisplayLink]; //displayLink needs to be removed from the run loop, otherwise it will keep going in the background and get corrupted. 
    [self show]; 
} 

이 경우 메모리 경고 메시지가 표시되지 않으므로 자원 부족으로 인한 것입니다.

누구나 이와 같은 문제가 발생 했습니까? 추가 정보가 필요하다면 제공 할 수는 있지만 게시 할 수있는 코드는 제한적입니다. 어떤 도움을 주시면 고맙겠습니다. 저는 2 주 동안이 문제를 해결하려고 노력해 왔지만 그것을 이해할 수는 없습니다.


편집 : 그것은 내가 뒤에 스크롤 뷰를 제거 할 때 문제가 사라집니다로 모두의 AlertView가 (또는 오히려 그냥 alertView되지 않음)하지 않은 것 같습니다, 그래서이 있어야합니다 일부 두 사람 사이의 문제. 이것은 내있는 UIScrollView 하위 클래스에 대한 코드입니다 : .H 파일 : # import를 # import를

@class ECSimulatorController; 
@interface UILogicSimulatorView : UIScrollView { 
    CADisplayLink *displayLink; 
    NSInteger _updateRate; 
    ECSimulatorController* _hostName; 
} 

@property (nonatomic) NSInteger updateRate; 
@property (nonatomic, strong) ECSimulatorController* hostName; 

- (void) removeDisplayLink; 
- (void) reAddDisplayLink; 

- (void) displayUpdated:(CADisplayLink*)timer; 
- (void) startRunning; 
- (void) stopRunning; 
- (void) refreshRate:(NSInteger)rate; 

- (void) setHost:(id)host; 

- (void)setMinimumNumberOfTouches:(NSInteger)touches; 
- (void)setMaximumNumberOfTouches:(NSInteger)touches; 

@end 

.파일 :

#import "UILogicSimulatorView.h" 
#import "ECSimulatorController.h" 
#import <QuartzCore/QuartzCore.h> 

@implementation UILogicSimulatorView 

@synthesize updateRate = _updateRate; 
@synthesize hostName = _hostName; 

- (void)reAddDisplayLink { 
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be re-added to the run loop after having been removed. 
} 

- (void)removeDisplayLink { 
    [displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be removed from the Run loop without deleting it. Removing it is essential to prevent corruption between the games and the simulator as both use CADisplay link, and only one can be in the run loop at a given moment. 
} 

- (void)startRunning { 
    [self refreshRate:self.updateRate]; 
    [displayLink setPaused:NO]; 
} 

- (void)refreshRate:(NSInteger)rate { 
    if (rate > 59) { 
     rate = 59; //prevent the rate from being set too an undefined value. 
    } 
    NSInteger frameInterval = 60 - rate; //rate is the number of frames to skip. There are 60FPS, so this converts to frame interval. 
    [displayLink setFrameInterval:frameInterval]; 
} 

- (void)stopRunning { 
    [displayLink setPaused:YES]; 
} 

- (void)displayUpdated:(CADisplayLink*)timer { 
    //call the function that the snakeController host needs to update 
    [self.hostName updateStates]; 
} 

- (void)setHost:(ECSimulatorController*)host; 
{ 
    self.hostName = host; //Host allows the CADisplay link to call a selector in the object which created this one. 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    //Locates the UIScrollView's gesture recogniser 
    if(self = [super initWithFrame:frame]) 
    { 
     [self setMinimumNumberOfTouches:2]; 
     displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayUpdated:)]; //CADisplayLink will update the logic gate states. 
     self.updateRate = 1; 
     [displayLink setPaused:YES]; 
    } 
    return self; 
} 

- (void)setMinimumNumberOfTouches:(NSInteger)touches{ 
    for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers]) 
    { 
     if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) 
     { 
      //Changes the minimum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger. 
      [(UIPanGestureRecognizer*)gestureRecognizer setMinimumNumberOfTouches:touches]; 
     } 
    } 
} 

- (void)setMaximumNumberOfTouches:(NSInteger)touches{ 
    for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers]) 
    { 
     if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) 
     { 
      //Changes the maximum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger. 
      [(UIPanGestureRecognizer*)gestureRecognizer setMaximumNumberOfTouches:touches]; 
     } 
    } 
} 

@end 
+0

"음, 절대 이미지를 게시 할 수 없습니까? 도움이되지 않습니다." 그것은 첫 번째 게시물입니다. 그러므로 우리는 당신을 신뢰하지 않습니다. 이것은 많은 잇점 중 하나입니다! – dasdom

+0

나는 왜 그렇게 많은 스패머들이 그러한 조치가 필요하다는 것을 짜증나게하는지 이해한다. –

+0

다른 백그라운드 (예 : 백그라운드)에서 알림보기를 표시하려고하십니까? 기억하십시오 : 메인 스레드에서 ** 항상 ** UI 작업을 수행하십시오! –

답변

0

나는이 질문에 대한 답변이 너무 늦었다 고 알고있다. 요즘 나는이 똑같은 문제를 경험했다.

내 케이스 : 몇 가지 사용자 정의 UIView에 배경 이미지와 일부 컨트롤이 그림자 효과로 스크롤보기에 추가되었습니다. shadowOffset도 설정했습니다.

는 솔루션 : 단계 분석하여 몇 가지 단계 후 , 나는 setShadowOpacity을 설정하는 것은 나를 위해 렌더링 문제가 발생하는 것을 발견했다. 그 코드 행에 주석을 달았을 때 UIAlertView가 정상적인 모양으로 복원되었습니다.

기타 : 확실히, 나는 shadowOpacity로 원본 UI를 모방 한 새로운 프로젝트를 만들었습니다. 하지만 그것은 예상대로 렌더링 문제가 발생하지 않았다. 그래서 나는 근본 원인에 대해 확신하지 못합니다. 나를 위해 그것은 setShadowOpacity이었다.

+0

너무 늦어서 질문에 답할 수 없습니다. 원래 setShadowOpacity를 어디에서든지 사용 했었는지 확실치 않았지만 이상한 결함은 앱의 다른 부분에서 그 추한 얼굴을 보여 줬습니다. 조금 파고 들자,이 앱을 위해 만든 템플릿 내부 깊숙한 곳에서 setShadowOpacity가 호출됩니다. 나는 라인 아웃과 결함이 치유되었다고 논평했다. (나는 왜 내가 그 방법을 처음에 불렀는지를 기억할 수 없다!). 대단히 고마워요 : D –

+0

당신은 오신 것을 환영합니다! 그게 행복 :) –

1

글쎄, 나는 이것을 해결할 수 있었다. 실제로 경로 원인을 찾는 것보다는 문제를 숨기는 것일 수도 있지만이 시점에서 내가 취할 것입니다.

우선 몇 가지 코드 :

@interface UIView (ViewCapture) 
- (UIImage*)captureView; 
- (UIImage*)captureViewInRect:(CGRect)rect; 
@end 

@implementation UIView (ViewCapture) 

- (UIImage*)captureView { 
    return [self captureViewInRect:self.frame]; 
} 

- (UIImage*)captureViewInRect:(CGRect)rect 
{  
    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    [self.layer renderInContext:context]; 
    UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return screenShot;  
} 
@end 

- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView { 
    [simulationView stopRunning]; 
    UIView* superView = simulationView.superview; 
    CGPoint oldOffset = simulationView.contentOffset; 
    for (UIView* subview in simulationView.subviews) { 
     //offset subviews so they appear when content offset is (0,0) 
     CGRect frame = subview.frame; 
     frame.origin.x -= oldOffset.x; 
     frame.origin.y -= oldOffset.y; 
     subview.frame = frame; 
    } 
    simulationView.contentOffset = CGPointZero; //set the offset to (0,0) 
    UIImage* image = [simulationView captureView]; //Capture the frame of the scrollview 
    simulationView.contentOffset = oldOffset; //restore the old offset 
    for (UIView* subview in simulationView.subviews) { 
     //Restore the original positions of the subviews 
     CGRect frame = subview.frame; 
     frame.origin.x += oldOffset.x; 
     frame.origin.y += oldOffset.y; 
     subview.frame = frame; 
    } 
    [simulationView setHidden:YES]; 
    UIImageView* imageView = [[UIImageView alloc] initWithFrame:simulationView.frame]; 
    [imageView setImage:image]; 
    [imageView setTag:999]; 
    [superView addSubview:imageView]; 
    [imageView setHidden:NO]; 
    superView = nil; 
    imageView = nil; 
    image = nil; 
    [self show]; 
} 

- (void)dismissUnpausingSimulation:(UILogicSimulatorView *)simulationView { 
    UIView* superView = simulationView.superview; 
    UIImageView* imageView = (UIImageView*)[superView viewWithTag:999]; 
    [imageView removeFromSuperview]; 
    imageView = nil; 
    superView = nil; 
    [simulationView setHidden:NO]; 
    [simulationView startRunning]; 
} 

가 그런 다음이 줄이 내 수업 시간에 대리자 메서드를 기각 수정 :

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 
    [alertView dismissUnpausingSimulation:self.simulationView]; 
    ... 

경고보기를 호출하지만이 표시되기 전에, I 경고를 손상시키지 않도록 시뮬레이터를 숨길 필요가 있습니다. 그러나 그저 숨어있는 것은 볼 수 없기 때문에 뒤에서 볼 수없는 것은 빈 화면입니다.

이 문제를 해결하려면 먼저 시뮬레이터에서 그래픽 컨텍스트를보고 UIImage를 만듭니다. 그런 다음 시뮬레이터와 동일한 프레임으로 UIImageView를 만들고 이미지로 UIImage를 설정합니다. 그런 다음 시뮬레이터보기를 숨기고 (경보 문제 해결) 새 UIImageView를 시뮬레이터 수퍼 뷰에 추가합니다. 나 또한 나중에 찾을 수 있도록 이미지보기의 태그를 설정합니다.

경고가 사라지면 이미지보기는 해당 태그를 기반으로 복구되고 수퍼 뷰에서 제거됩니다. 시뮬레이터는 숨김 상태가 아닙니다.

결과적으로 렌더링 문제가 해결되었습니다.