2016-08-12 4 views
0

Facebook Graph API를 사용하여 UIImageView에 표시하려는 200x200 프로필 사진의 문자열 URL을 검색했습니다. 나는 성공적으로이 작업을 수행 할 수 있지만 이미지가 화면에 표시되는 데 10 초 정도 걸릴 수 있습니다. 아무도 날 포인터 (어떤 말장난 의도) 그것을 최적화하는 방법에 줄 수 있습니까?로딩 이미지가 너무 오래 걸리는 경우

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 

    NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: self.profilePictureUrl)!, completionHandler: { (data, response, error) -> 
     Void in 
     self.profilePictureImageView.image = UIImage(data: data!) 
     self.profilePictureImageView.layer.cornerRadius = self.profilePictureImageView.frame.size.width/2; 
     self.profilePictureImageView.clipsToBounds  = true 

     dispatch_async(dispatch_get_main_queue(), {() -> Void in 
      self.view.addSubview(self.profilePictureImageView) 
     }) 

    }).resume() 
} 
+0

비동기 호출 외부에서 하위보기를 추가 한 다음 완료 블록의 하위보기 이미지 만 설정하면됩니까? – brandonscript

답변

3

당신은 스레드로부터 안전하지 않습니다 대부분의 UIKit으로 메인 스레드에 모든 UIView 전화 (당신이 UIImageView에 설정 때문에 무엇이든) 이동해야합니다. 당신은 성능 최적화를 위해 비록 배경 스레드에서 UIImage의 인스턴스를, 그래서이 시도 할 수 있습니다 : 나는 weakself에 대한 참조를 -ified했습니다 것 또한

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 

    let url = NSURL(string: self.profilePictureUrl)! 

    NSURLSession.sharedSession().dataTaskWithURL(
     url, 
     completionHandler: { [weak self] (data, response, error) -> Void in 
      guard let strongSelf = self else { return } 

      // create the UIImage on the background thread 
      let image = UIImage(data: data!) 

      // then jump to the main thread to modify your UIImageView 
      dispatch_async(dispatch_get_main_queue(), { [weak self]() -> Void in 
       guard let strongSelf = self else { return } 

       let profilePictureImageView = strongSelf.profilePictureImageView 

       profilePictureImageView.image = image 
       profilePictureImageView.layer.cornerRadius = profilePictureImageView.frame.size.width/2; 
       profilePictureImageView.clipsToBounds = true 

       strongSelf.view.addSubview(profilePictureImageView) 
      }) 
     } 
    ).resume() 
} 

참고. 완료 루틴이 호출 될 때까지 사용자가이 코드를 시작하는보기 컨트롤러를 닫지 않았다고 보장하지 않으므로 self에 대한 강력한 참조가 유지되지 않도록해야합니다. 이렇게하면 사용자가 불필요한 작업을 수행하지 않고 완료 루틴을 일찍 반환하면보기 컨트롤러가 할당을 해제 할 수 있습니다.

+0

이러한 모든 개선에 감사드립니다. 저는 호기심이 있습니다 - 의도적으로'strongSelf'에 대한 두 개의 참조를 만들었습니까? Xcode가 이러한 선언 중 하나에 대해 경고를하기 때문에 나는 묻습니다. – AlexanderHart

+0

예, 각 콜백은 잠재적으로 스레드를 홉 (hop)하기 때문에 'strongSelf'에 대한 두 개의 참조가 필요합니다. Xcode가 변수 이름 중 하나를 변경해야한다고 불평하면, 예를 들어 내부 클래스를'strongSelfInner'로 만드십시오. – par

0

이 코드는 불법입니다 :

NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: self.profilePictureUrl)!, completionHandler: { (data, response, error) -> 
    Void in 
    self.profilePictureImageView.image = UIImage(data: data!) 

그만! UIImageView의 이미지를 배경 스레드에 으로 설정하고 있습니다. 아니, 아니. UIKit은 스레드로부터 안전하지 않습니다. 이 작업을 수행하려면 주 스레드로 이동해야합니다. (결국 코드에서 주 스레드로 이동하지만 너무 늦게 처리하고 있습니다.)

관련 문제