2017-01-07 2 views
3

나는 3 × 아이폰 5의하는 5 초, 6, 기가, 그리고 7EXC_BAD_ACCESS 코드 = EXC_ARM_DA_ALIGN

내가 5 장치에만 아이폰의 모든에 위의 오류를 받고 있어요 내 코드를 테스트했습니다. 여기서 무슨 일이 벌어지고 있는지 모르겠지만 5 비트가 32 비트 장치라는 사실은 단서 일 수 있습니까?

struct Configuration { 
    var userId: String = "Unknown" 
    var deviceType: DeviceType = .phone // enum: String 
    var deviceSide: DeviceSide = .notApplicable // enum: String 
    var deviceNumber: Int16 = 1 
    var devicePosition: DevicePosition = .waist // enum: String 
} 

CoreDataStack가 여기에 있습니다 : :

final class CoreDataStack { 
    static let shared = CoreDataStack() 
    private init() {} 

    var errorHandler: (Error) -> Void = { error in 
      log.error("\(error), \(error._userInfo)") 
    } 

    private struct constants { 
      static let persistentStoreName = "Model" 
    } 

    private lazy var persistentContainer: NSPersistentContainer = { 
      let container = NSPersistentContainer(name: constants.persistentStoreName) 
      container.loadPersistentStores(completionHandler: { [weak self] (storeDescription, error) in 
        if let error = error { 
          self?.errorHandler(error) 
        } 
      }) 
      return container 
    }() 

    lazy var viewContext: NSManagedObjectContext = { 
      self.persistentContainer.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump 
      self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true 
      try! self.persistentContainer.viewContext.setQueryGenerationFrom(.current) 
      return self.persistentContainer.viewContext 
    }() 

    private lazy var backgroundContext: NSManagedObjectContext = { 
      let context = self.persistentContainer.newBackgroundContext() 
      context.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump 
      return context 
    }() 

    func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) { 
      self.viewContext.performAndWait { 
        block(self.viewContext) 
      } 
    } 

    func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) { 
      backgroundContext.perform { 
        block(self.backgroundContext) 
      } 
    } 

    func saveBackgroundContext() { 
      viewContext.performAndWait { 
        do { 
          if self.viewContext.hasChanges { 
            try self.viewContext.save() 
          } 
        } catch { 
          self.errorHandler(error) 
        } 

        self.backgroundContext.perform { 
          do { 
            if self.backgroundContext.hasChanges { 
              try self.backgroundContext.save() 
              self.backgroundContext.refreshAllObjects() 
            } 
          } catch { 
            self.errorHandler(error) 
          } 
        } 
      } 
    } 

    func saveViewContext() { 
      viewContext.perform { 
        if self.viewContext.hasChanges { 
          do { 
            try self.viewContext.save() 
          } catch { 
            self.errorHandler(error) 
          } 
        } 
      } 
    } 

    func saveViewContextAndWait() { 
      viewContext.performAndWait { 
        if self.viewContext.hasChanges { 
          do { 
            try self.viewContext.save() 
          } catch { 
            self.errorHandler(error) 
          } 
        } 
      } 
    } 
} 

나는의 ViewController 클래스

func startRecording() { 
    disableControls() 

    CoreDataStack.shared.performForegroundTask { (context) in 
      let sessionInfo = SessionInfo(context: context) 
      sessionInfo.startTime = Date().timeIntervalSince1970 
      sessionInfo.userId = self.config.userId 
      sessionInfo.devicePosition = self.config.devicePosition.rawValue 
      sessionInfo.deviceType = self.config.deviceType.rawValue 
      sessionInfo.deviceNumber = self.config.deviceNumber 
      sessionInfo.deviceSide = self.config.deviceSide.rawValue 

      do { 
        try context.obtainPermanentIDs(for: [sessionInfo]) 
      } catch { 
        print("Error obtaining permanent ID for session info record") 
        return 
      } 

      CoreDataStack.shared.saveViewContextAndWait() 

      DispatchQueue.main.async { 
        guard sessionInfo.objectID.isTemporaryID == false else { 
          print("ObjectID is temporary") 
          return 
        } 

        self.recording = true 
        self.statusLabel.text = "Recording..." 
        self.recordManager.start(sessionUID: sessionInfo.uid) 
      } 
    } 
} 

는 config 변수에서 다음 메소드를 호출하고있어 간단한 구조체이다 코드는 startRecording 방법의 다음 줄에서 폭격합니다.

try context.obtainPermanentIDs(for: [sessionInfo]) 

편집 :

내가 구성된 벗었 테스트 응용 프로그램을 만든 경우에만 CoreDataStack 입력 문자열의 하나 개의 속성을 가진 하나의 엔티티와 모델. 3x iPhone 5에서만 여전히 같은 오류가 발생합니다. 5s, 6, 6s, 7 모두 잘 작동합니다.

아마도 CoreDataStack에 문제가있는 것입니까?

Github에서의 환매 특약 here

+0

github 프로젝트에 CoreDataStack.swift 파일이 없습니다. 여기에서 복사하면 '로그'를 사용할 수 없습니다. '로그 아웃'하고 댓글을 달고 iPhone 5를 포함한 모든 시뮬레이터에서 '성공'을 얻습니다. 시뮬레이터 또는 실제 장비에서만 오류가 발생합니까? – oyalhi

+0

이 문제에 대한 해결책이나 해결 방법을 찾으셨습니까? 나는 거의 같은 문제를 가지고 있으며 그것을 파악할 수 없다. –

답변

0

난 당신의 코드에서 짧은 모양을 기반으로 추측 소요될 수 있습니다.

저의 오래된 학교 개발자는 구성 멤버 var deviceNumber: Int16 = 1에 그려져 있습니다. 잘못된 맞춤 설정 또는 오래된 컴파일러로 인해 다음 항목의 정렬이 잘못 될 수 있습니다. 구조체의 마지막 항목으로 만들 수도 있습니다.

다른 두드러진 항목은 sessionInfo.deviceNumber = self.config.deviceNumber입니다. 이것은 문제가 될 수있는 NSNumber에 Int16을 할당하는 것으로 보입니다. (나는 SessionInfo는 전체 코드와 그 초기화 컨텍스트 인수를 복용 기반으로 NSManagedObject이라고 가정하고있다. 즉, 모든 숫자 회원 NSNumbers 있습니다 의미합니다.)

sessionInfo.deviceNumber = NSNumber(int:self.config.deviceNumber) 

나 '에 선을 변경해보십시오 코어 데이터에 추가 된 iOS 10에 익숙하지 않지만 viewContext를 읽는 사람은 읽기 전용입니다. 그러나 viewContext는이 코드에서 새 객체를 만드는 데 사용됩니다. 디버거에서이 시점에 도달하면 Xcode 콘솔에 더 많은 정보가 표시됩니까?

+0

제안 해 주셔서 감사합니다. 나는 그것을 시도하고 문제를 해결하기 위해 내가 생각할 수있는 모든 것을 제거했지만 아무것도 효과가 없었다. 문제를 복제하는 데 필요한 최소 코드로 새 프로젝트를 만들었습니다. repo 링크에 대해 편집 된 질문을 참조하십시오. 당신이 볼 수 있다면 감사하겠습니다! – doovers

+0

두 부분을 모두 사용해 보셨습니까? NSNumber 부분은 어떻습니까? (나는 샘플 라인을 포함시키기 위해 나의 대답을 편집했다.) –

+0

예 NSNumber도 시도했다. 그러나 샘플 프로젝트에서 모든 숫자를 제거하고 엔티티에 단일 문자열 속성 만 있고 여전히 발생합니다. – doovers

0

NSPersistentContainer은 사용 방법에 대한 명확한 예상과 함께 핵심 데이터 스택을위한 설정입니다. 당신은 그것을 오용하고 있습니다. viewContext은 읽기 전용이므로 performForegroundTask, saveViewContextsaveViewContextAndWait을 제거하십시오. viewContext의 mergePolicy를 변경하지 마십시오. performBackgroundTask에서 NSPersistentContainer의 performBackgroundTask는 동일한 메소드 서명을 사용합니다. newBackgroundContext을 사용하지 마십시오. NSPersistentContainer을 사용하는 경우 CoreDataStack은 아무 것도하지 말아야합니다.

NSPersistentContainer과 다른 맞춤 스택을 원할 경우 NSPersistentContainer을 사용하지 말고 직접 스택을 만드십시오. 그러나 작성하려는 설정에는 큰 문제가 있습니다. 쓰기가 동시에 발생하면 배경 컨텍스트와 viewContext에서 모두 쓰기 문제가 있습니다. mergePolicy를 사용하면 도움이되지만 저장 한 정보가 누락 될 수 있습니다. 너는 NSPersistentContainer이 설정 한 스택을 사용하는 법을 배우는 것이 훨씬 낫다.

+0

제안에 감사드립니다. 당신이 말하는 것은 의미가 있지만, 명확하지 않은 것은 왜 newBackgroundContext를 사용할 수 없는지입니다. 내가하고있는 이유는 공통 컨텍스트에서 여러 객체를 만들고 일괄 적으로 저장하여 I/O를 제한하기를 원하기 때문입니다. 그 contra 표시되어 있습니까? 또한, 좋은 리소스가 있다면'NSPersistentContainer'의 적절한 사용에 대한 좋은 참고 자료를 가르쳐 주시겠습니까? – doovers

+0

일괄 처리로 저장하는 것이 좋습니다. 이를 수행하기 위해'performBackgroundTask'를 사용할 것을 제안합니다. newBackgroundContext보다 많은 장점이 있습니다. 먼저 코드가 올바른 스레드에서 실행되도록합니다. 둘째, 동시에 두 번의 쓰기가 발생하지 않도록합니다. 셋째, 이러한 문맥은 일회용이라는 명확한 기대를합니다 - 당신은 당신의 블록에서 사용하고 다시 사용하지 마십시오. 주변 컨텍스트를 유지하는 것보다 더 나은 시스템이라는 것을 알았습니다. –

+0

나는 조금 혼란스러워. 'performBackgroundTask' 호출을 여러 번 사용하여 엔티티를 생성하면 어떻게 일괄 적으로 저장할 수 있습니까? 한 블록에 모든 엔티티를 생성 할 수 없기 때문에 새로운 엔티티 각각에 대한 공통 컨텍스트를 생성하기 위해 'newBackgroundContext'를 사용하는 이유를 추론합니다. 내가 여기서 무엇을 놓치고 있니? – doovers