내 프로그램이 완벽하게 작동합니다. 내 인생에 너에게 보증 해, 0 벌레. 자랑스럽게, 나는 TestFlight를 사용하여 베타 테스터에 ad-hoc 배포를위한 .ipa 파일로 애플리케이션을 패키징하려고 시도했다.
프로그램이 작동하지 않았습니다. 일어날 일이없는 애니메이션은 절대로 일어나지 않습니다. 네트워크 코드가 끊어집니다. 음악을 아름답게 사라지게하는 버튼은 아무 것도하지 않았습니다.
범인은 새롭고 빛나는 블록 인 것으로 나타났습니다. 시뮬레이터 나 장치에서 프로그램을 테스트 할 때 기본 "디버그"빌드 구성을 사용했습니다. 그러나 배포를 위해 보관하면 (그리고 나중에 App Store에 제출할 것을 믿습니다), XCode는 "릴리스"라는 또 다른 구성을 사용합니다. 추가로 조사한 차이점은 최적화 수준 (Xcode의 빌드 설정에서 찾을 수 있음) 때문입니다. 디버그는 없음 (-O0)을 사용하지만 릴리스는 가장 빠름, 최소 (-O)를 사용합니다. 나는 그것이 가장 빠르다, 가장 작다, 그리고 일하지 않는다는 것을 거의 알지 못했다. 예, 블록은 두 가지 구성에서 다르게 동작합니다.
그래서 문제를 해결하기 위해 착수했습니다. 세상에 곧 바뀌는 앱을 본인의 뼈에 단순화했습니다.이 게시물에 첨부 된 이미지에 나와 있습니다. View Controller는 초기 값이 0 인 인스턴스 변수 x를가집니다. b를 누르면 x가 1이 될 때 맨 아래 레이블을 변경하면서 x의 값을 계속 확인할 스레드를 생성합니다. x 값을 변경할 수 있습니다 에이. 여기
(나는 BTW ARC를 사용하고 있습니다) 내 순진 코드 :@implementation MBIViewController
{
int _x;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_x = 0;
}
- (void)updateLabel
{
self.topLabel.text = [NSString stringWithFormat:@"x: %d", _x];
}
- (IBAction)buttonAPressed:(id)sender {
_x = 1;
[self updateLabel];
}
- (IBAction)buttonBPressed:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (_x != 1) {
// keep observing for value change
}
dispatch_async(dispatch_get_main_queue(), ^{
self.bottomLabel.text = @"b changed me becase x changed!";
});
});
}
@end
_x는 인스턴스 변수이므로 블록 포인터를 "자기"를 사용하여 액세스 할 것이라고 생각하는 것이 합리적이다 로컬 복사본이 아닙니다. 디버그 구성에서 작동합니다!
그러나 릴리스 빌드에서는 작동하지 않습니다. 아마 그 블록은 로컬 복사본을 사용하고있을 것입니다. 자, 명시 적으로 자체를 사용합시다.
while (self->_x != 1) {
// keep observing for value change
}
릴리스에서 작동하지 않습니다. 좋아요, 포인터를 사용하여 직접 변수에 접근 해 봅시다 :
int *pointerToX = &_x;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (*pointerToX != 1) {
// keep observing for value change
}
// other codes
});
여전히 작동하지 않습니다. 이것은 똑똑한 최적화 컴파일러가이 멀티 스레드 세계에서 비교 결과가 바뀔 가능성이 없다고 가정하기 때문에 항상 TRUE 또는 다른 부두가되도록 대체했을 것입니다.
내가이를 사용할 때지금, 상황이 다시 작업을 시작 :
- (int)x
{
return _x;
}
: 그리고
while (_x != 1) {
// keep observing for value change
NSLog(@"%d", _x);
}
을 그래서 컴파일러는 비교를 최적화 우회, 나는 게터를 만들기 위해 의지 해당 게터를 사용하여 값을 확인하십시오 :
while (self.x != 1) {
// keep observing for value change
}
이제 self.x는 실제로 ca입니다. 컴파일러는 실제로 함수를 수행 할 수 있도록 충분히 정중합니다. 그러나, 나는 이것이 매우 단순한 일을하는 다소 복잡한 방식이라고 생각한다. "블록 내부의 가치 변화를 관찰"하는 작업에 직면 한 경우 다른 방법으로 코드화했을 것입니다. 또 다른 패턴을 사용할 것입니까? 고마워요!
와우, 휘발성 키워드 작동합니다! 나는 한 번 C 책을 읽었던 것을 기억하고 결코 그것을 사용하지 않을 것이라고 상상하지 못했습니다! 감사합니다 – agro1986
와우 ... 참으로 .. :) +1 : – TonyMkenu