2016-11-04 3 views
1

저는 Apple의 GCD를 처음 접했고 DispatchGroup에 문제가 있습니다. 그래서 게시물이 완전히 초기화 된 후지도에 게시물을 첨부하려고합니다. post.init 안에는 URLSession이 있으며 URL에서 UIImage을 다운로드합니다. 그러나 다운로드가 완료되기 전에도 group.notify이 (가) 종료됩니다. 나는 그 이유가 무엇인지 알 수 없다. 아래는 코드입니다. 어떤 조언이나 도움을 주셔서 감사합니다! 감사.작업이 완료되기 전에 파견 그룹이 알립니다.

// ViewController.swift 
let group = DispatchGroup 
... 
... 

group.enter() 
DispatchQueue.global(qos: .userInitiated).async { 
    post = Post(values: post) 
    self.posts[postId] = post 
    group.leave() 
} 

group.notify(queue: DispatchQueue.main, execute: { 
    print("notify:: \(post?.picture)") // This prints out nil, when it shouldn't. 
    self.addPostToMap(post!, at: location!) 
}) 

// Post.swift 
class Post { 
    var picture: UIImage? 
    var thumbnail: UIImage? 
    init(values: [String: Any]) { 
     ... 
     URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in 
      DispatchQueue.main.async { 
       self.picture = UIImage(data: data!) 
       self.thumbnail = Util.resizeImage(image: self.picture!, targetSize: CGSize(width: 50, height: 50)) 
      } 

     }).resume() 

    } 

} 

답변

2

init (values ​​:)의 완료 핸들러는 작업이 완료 될 때마다 트리거됩니다. 그러나 .resume() 호출 후 코드 실행이 계속됩니다. 즉 init이 종료되고 group.notify 블록이 즉시 호출됩니다.

다양한 방법으로 처리 할 수 ​​있습니다. 하나는 Post 클래스에 대한 델리게이트 프로토콜을 설정하고 ViewController를 해당 델리게이트로 설정하는 것입니다. 완료 핸들러에서 함수 호출 - 인수 호출을 위해 didFinish() - 뷰 컨트롤러에 태스크가 완료되었음을 알립니다. 해당 함수에서 알림을 래핑 할 수 있습니다.

이런 식으로 일을 처리하지만, 나는 init 함수에서 dataTask를 제거합니다. 그 이유는 대개 대리자가 암시 적으로 래핑되지 않은 선택 사항으로 선언되고 작성 클래스에서 설정되기 때문입니다. 따라서 클래스를 초기화 할 때 대리자 콜백을 호출 할 때 대리자가 아무 것도 참조하지 않을 가능성이 있습니다. 다음과 같이

그래서 구조는 다음과 같습니다

// ViewController.swift 
class ViewController : UIViewController, PostDelegate { 
    let group = DispatchGroup 
    ... 
    ... 

    group.enter() 
    DispatchQueue.global(qos: .userInitiated).async { 
     post = Post(values: post) 
     post.delegate = self 
     post.getImage() // New function 
     self.posts[postId] = post 
     group.leave() 
    } 

    .... 

    func didFinish() -> Void { 
     group.notify(queue: DispatchQueue.main, execute: { 
      print("notify:: \(post?.picture)") 
      self.addPostToMap(post!, at: location!) 
    }) 

    .... 

Protocol PostDelegate { 
    func didFinish() -> Void 
} 

// Post.swift 
class Post { 
    var delegate : PostDelegate! 
    var picture: UIImage? 
    var thumbnail: UIImage? 
    init(values: [String: Any]) { 
    ... 
    } 

    func getImage() -> Void { 
     URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in 
      DispatchQueue.main.async { 
       self.picture = UIImage(data: data!) 
       self.thumbnail = Util.resizeImage(image: self.picture!, targetSize: CGSize(width: 50, height: 50)) 
       if delegate != nil { 
        delegate.didFinish() // Tell the delegate you are done 
       } 
      } 

     }).resume() 

    } 

} 

의미가 희망, 그리고 더 중요한 것은 도움이!

+0

답장을 보내 주셔서 감사합니다. 그러나 didFinish에서 변수'post' 및'location'에 액세스 할 수 없으므로 알림을받는 것이 문제가됩니다. 이것에 대한 제안? –

+0

사실 나는 그것을 만들었다! 위임 메서드를 통해 변수를 전달했습니다. 감사! –

관련 문제