2017-04-13 1 views
2

UIViewUIViewController에서 대리인 메서드로 업데이트하고 싶습니다.대리자 함수에서 UIControllerView를 업데이트 할 수 없습니다.

사용자가 UIViewController에서 다운로드를 다운로드하고, 다운로드가 UploadAsyncData이 완료되면 다운로드가 다른 클래스에 처리 된 응답을 전달할 때 클래스에 의해 관리됩니다. 이 클래스는받은 데이터를 로컬 데이터베이스에 씁니다.

사용자에게 프로세스 진행 상황 인 UIViewController을 던지라고 알려 드리고 싶습니다.

지금에서 수행 한 어떤

다음 UIViewController에서

  • 내가 그것에 일부 메시지와 함께 Overlay을 나타내는 UIView을 얻었다. UIView도 외부에서 참조 할 수 있도록 정적 도우미 클래스로 설정됩니다.

  • 사용자가 다운로드 버튼을 누르면 Overlay이 나타나고 사용자에게 조치가 취해 졌음을 알립니다.

  • 조치는 Overlay 텍스트가 업데이트됩니다 다운로드 클래스에 전달됩니다 다운로드는 응답이 Overlay 텍스트를 업데이트 처리 다운로드 클래스의 메소드를 완료

  • "다운로드가 진행 중입니다" "다운로드 완료, 수신 된 데이터 처리 중 ..."

  • 받는 데이터가 C# 개체이므로이 개체에서 SaveToDatabase 메서드를 호출합니다.

  • SaveToDatabase 메서드는 진행률 표시기로 Overlay을 업데이트합니다.

지금까지 모든 단계를 올바르게 SaveToDatabase 단계를 제외하고 Overlay 메시지를 업데이트하고 있습니다. 디버깅 할 때마다 Overlay 텍스트가 각 단계에서 호출되고 있지만 UIView 텍스트는 업데이트되지 않습니다.

SaveToDatabase가 UIViewController이 아니므로 InvokeOnMainThread을 사용할 수 없습니다. 모든 단계가 올바르게 UIView가 마지막으로 업데이트되는 이유는 무엇인지 이해할 수 없습니다.

다음은이 단계의 일부 코드입니다.서버 응답을 처리 downloadAction

public class HttpCommunication 
{ 
    {...} 
    public HttpCommunication(Parametrage parameters, HttpResponseAction responseAction) 
    { 
     client = new XSWebClient(); 
     client.UploadDataCompleted += OnUploadDataCompleted; 
    } 

    public void DoRequest(Request JRequest) 
    { 
     {...} 
     SendRequest(); 
    } 

    void SendRequest() 
    { 
     {...} 
     client.UploadDataAsync(Request.Uri, "POST", bytes); 
     {...} 
    } 

    void OnUploadDataCompleted(object sender, UploadDataCompletedEventArgs e) 
    { 
     Helpers.UpdateOverlayMessage("Processing recieved response..."); 
     {...} 
     HandleResponse handler = new HandleResponse(myParameters, e.Result); 
     {...} 
    } 
} 

클래스 처리

주요 방법

public class Program:UIViewController 
{ 
    {...} 
    public override void ViewDidLoad() 
    { 
     base.ViewDidLoad(); 
     AddOverlay(); 
    } 

    public void AddOverlay() 
    { 
     var bounds = UIScreen.MainScreen.Bounds; 
     bounds.Size = new CGSize(bounds.Size.Width, bounds.Size.Height); 
     loadingOverlay = new LoadingOverlay(bounds); 
     loadingOverlay.Hidden = true; 

     View.Add(loadingOverlay); 
     System.Diagnostics.Debug.WriteLine(this.GetType().Name + loadingOverlay.GetHashCode()); 
     Helpers.LoadingOverlay = loadingOverlay; 
    } 

    public void DisplayOverlay(string text) 
    { 
     if(loadingOverlay != null){ 
      View.BringSubviewToFront(loadingOverlay); 
      System.Diagnostics.Debug.WriteLine(this.GetType().Name + loadingOverlay.GetHashCode()); 
      loadingOverlay.Hidden = false; 
      loadingOverlay.SetLoadingLabel(text); 
     } 
    } 

    void Tablesource_OnRowSelected(object sender, eConversion5.DownloadTableSource.RowSelectedEventArgs e) 
    { 
     bool isReacheable = myParameters.IsReachable(); 
     if (isReacheable) { 
      DisplayOverlay("Your download is about to start..."); 
      Request request = new Request(url, myParameters); 
      request.CanBeSaved = false; 
      request.Action = "display"; 
      httpCommunication.DoRequest(request); 
     } 
    } 
} 

방법

public class HttpResponseAction 
{ 
    {...} 
    public void ExecuteAction(HandleResponse handled, Request request) 
    { 
     {...} 
     Helpers.UpdateOverlayMessage("Processing response..."); 
     {...} 
     HandleTrainings(queryId, action, JsonConvert.DeserializeObject<List<TrainingContainer>>(json, Settings)); 
     {...} 
    } 

    void HandleFormation(string queryId, string action, object nestedResult) 
    { 
     {...} 
     if (action == "display") { 
      result.SaveToDatabase(); 
      {...} 
     } 
     {...} 
    } 

} 

그리고 마지막 단계는 UIView의 (모든 단계가 그 전에 제대로 업데이트하는)

public class TrainingContainer 
{ 
    {...} 
    public void SaveToDatabase() 
    { 
     if(SignList != null){ 
      Helpers.UpdateOverlayMessage("Updating sign list in progress, may be take a while..."); 
      int updated = 0; 
      int total = SignList.Count(); 
      if(total > 0){ 
       foreach (Training training in SignList) { 
        updated++; 
        float progress = (float) updated/total; 
        Helpers.UpdateProgressValue(progress); //From debbuging, i can see that this method is called, and Overlay object is the same throw all class calls from the starting point. 
        {...} 
       } 
      } 
     } 
     {...} 
    } 
} 

헬퍼 클래스

public static class Helpers 
{ 
    public static LoadingOverlay LoadingOverlay; 
    {...} 
    public static void UpdateOverlayMessage(string message) 
    { 
     if(LoadingOverlay != null){ 
      StackTrace stackTrace = new StackTrace(); 
      System.Diagnostics.Debug.WriteLine(typeof(Helpers).Name + " (called from " + stackTrace.GetFrame(1).GetMethod().Name + ")" + LoadingOverlay.GetHashCode()); 

      LoadingOverlay.SetLoadingLabel(message); 
     } 
    } 

    public static void UpdateProgressValue(float progessValue) 
    { 
     if (LoadingOverlay != null) { 
      StackTrace stackTrace = new StackTrace(); 
      System.Diagnostics.Debug.WriteLine(typeof(Helpers).Name + " (called from " + stackTrace.GetFrame(1).GetMethod().Name + ")" + LoadingOverlay.GetHashCode()); 
      LoadingOverlay.UpdateProgress(progessValue); 
     } 
    } 
} 

편집을 업데이트하지 않는 것이 : 어떤 흔적에 대한 호출에서 로그인 돕는 사람.

Helpers <UpdateOverlayMessage> :Transmitting request to the server...(called from Apply) -2037862263 
Helpers <UpdateOverlayMessage> :Processing recieved response...(called from Apply) -2037862263 
Helpers <UpdateOverlayMessage> :Processing response...(called from Apply) -2037862263 
Helpers <UpdateOverlayMessage> :Updating sign list in progress, may be take a while...(called from Apply) -2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 
Helpers <UpdateProgressValue> (called from Apply)-2037862263 

업데이트 2 : 는

public class LoadingOverlay : UIView { 
     // control declarations 
     UIActivityIndicatorView activitySpinner; 
     UILabel loadingLabel; 
     UIProgressView progressView; 

     public LoadingOverlay (CGRect frame) : base (frame) 
     { 
      // configurable bits 

      BackgroundColor = UIColor.Black; 
      Alpha = 0.55f; 
      AutoresizingMask = UIViewAutoresizing.All; 

      nfloat labelHeight = 22; 
      nfloat labelWidth = Frame.Width - 20; 

      // derive the center x and y 
      nfloat centerX = Frame.Width/2; 
      nfloat centerY = Frame.Height/2; 

      // create the activity spinner, center it horizontall and put it 5 points above center x 
      activitySpinner = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.WhiteLarge); 
      activitySpinner.Frame = new CGRect ( 
       centerX - (activitySpinner.Frame.Width/2) , 
       centerY - activitySpinner.Frame.Height - 20 , 
       activitySpinner.Frame.Width, 
       activitySpinner.Frame.Height); 
      activitySpinner.AutoresizingMask = UIViewAutoresizing.All; 
      AddSubview (activitySpinner); 
      activitySpinner.StartAnimating(); 

      // create and configure the "Loading Data" label 
      loadingLabel = new UILabel(new CGRect (
       centerX - (labelWidth/2), 
       centerY + 20 , 
       labelWidth , 
       labelHeight 
      )); 
      loadingLabel.BackgroundColor = UIColor.Clear; 
      loadingLabel.TextColor = UIColor.White; 
      loadingLabel.Text = "Wait a moment..."; 
      loadingLabel.TextAlignment = UITextAlignment.Center; 
      loadingLabel.AutoresizingMask = UIViewAutoresizing.All; 
      AddSubview (loadingLabel); 

      progressView = new UIProgressView(); 
      progressView.Progress = 0.0f; 
      var screenParts = Frame.Width/3; 
      progressView.Frame = new CGRect(new CGPoint(screenParts,loadingLabel.Frame.Y + loadingLabel.Frame.Height + 20), new CGSize(screenParts,40)); 
      progressView.Hidden = true; 

      AddSubview(progressView); 
     } 

     /// <summary> 
     /// Fades out the control and then removes it from the super view 
     /// </summary> 
     public void Hide() 
     { 
      progressView.Progress = 0.0f; 
      InvokeOnMainThread(() => { 
       UIView.Animate(
        0.5, // duration 
        () => { Alpha = 0; }, 
        () => { RemoveFromSuperview(); } 
       ); 
      }); 
     } 

     public void SetLoadingLabel(String text) 
     { 
      InvokeOnMainThread(() => { 
       loadingLabel.Text = text; 
      }); 
     } 

     public void UpdateProgress(float progressValue){ 
      if(progressView.Hidden){ 
       progressView.Hidden = false; 
      } 
      if(progressValue > 1){ 
       progressValue = 1; 
      } 
      InvokeOnMainThread(() => { 
       progressView.SetProgress(progressValue, true); 
      }); 
     } 
    } 

답변

2

당신은 UI를 업데이트 할 때 메인 스레드에서 실행중인 있는지 확인 오버레이 클래스를 보여 잊으. InvokeOnMainThread 메서드는 NSObject에서 정의되므로 NSObject에서 상속 된 Helper 클래스를 만듭니다.

내가 클래스 형식을 변경해야
Helpers.Instance.UpdateOverlayMessage("..."); 
+0

, 정적 클래스는 Object에서 파생 할 수 없습니다

Helpers.Instance.LoadingOverlay = loadingOverlay; 

하는 UI를 업데이트하는 경우 : 주요 방법에서

 public sealed class Helpers:NSObject { public LoadingOverlay LoadingOverlay; private static readonly Helpers instance = new Helpers(); private Helpers(){} public static Helpers Instance { get { return instance; } } public void UpdateOverlayMessage(string message) { InvokeOnMainThread (() => { if(LoadingOverlay != null){ StackTrace stackTrace = new StackTrace(); System.Diagnostics.Debug.WriteLine(typeof(Helpers).Name + " (called from " + stackTrace.GetFrame(1).GetMethod().Name + ")" + LoadingOverlay.GetHashCode()); LoadingOverlay.SetLoadingLabel(message); } }); } //So does the method "UpdateProgressValue". } 

: 그래서 도우미 클래스는 같은 개선 될 수 . 그래서 클래스 모델을 다시 생각해야합니다, 나는 이미 내 애플 리케이션과 메모리 문제가있어 개체 사이에 강한 참조를 만들 수있는 패턴을 피하기 위해 싶습니다. – SunLiker67

+0

아, 정적 클래스가 NSObject에서 상속받을 수 없기 때문에 Singleton 패턴을 사용하여이를 수행 할 수 있습니다. 내 대답에 그것을 업데이 트하려고합니다. –

+0

이 업데이트에서는 DoRequest에서 오버레이 업데이트를 중지합니다. – SunLiker67

관련 문제