2012-07-11 35 views
1

我目前正在爲Monotouch框架製作一個應用程序,該框架具有帶有包含UISwitches的自定義UITableViewCell(用XCode設計)的UITableView。Monotouch UISwitch.valueChanged委託目標錯誤

我通過UITableViewSource管理單元,但在管理分配給事件UISwitch.ValueChanged的委託方法的回調時,我顯然遇到了問題。

這裏是UITableViewSource代碼我的工作,它可能是更明確:

 // This class manages the TableView content and its rows 
    class MyTableViewDelegate : UITableViewSource 
    { 
     SatellitesViewController  satController; 

     List<long>      allocatedCells; 

     public MyTableViewDelegate (SatellitesViewController controller) 
     { 
      satController = controller; 
      allocatedCells = new List<long>(); 
     } 

     public override int  RowsInSection (UITableView tableview, int section) 
     { 
      return satController.sats.Count; 
     } 

     // Called when the switch to show the satellite's display state is touched 
     public void    showButtonHandler(object sender, EventArgs e) 
     { 
      System.Console.WriteLine("SHOW BUTTONHANDLER"); 
      if (sender != null) 
      { 
       CustomSwitch switchButton = (CustomSwitch) sender; 
       TLEForRedis  satToShow = this.satController.getSatTLEs(switchButton.idSat, false); 

       if (satToShow != null) 
       { 
        if (switchButton.On == true) 
         this.satController.glView.showSatellite(satToShow); 
        else 
         this.satController.glView.hideSatellite(satToShow.Id); 
       } 
      } 
     } 

     // Called when the switch to show the satellite's display state is touched 
     public void    orbitButtonHandler(object sender, EventArgs e) 
     { 
      System.Console.WriteLine("ORBIT BUTTONHANDLER"); 
      if (sender != null) 
      { 
       CustomSwitch orbitButton = (CustomSwitch) sender; 
       TLEForRedis  satToShow = this.satController.getSatTLEs(orbitButton.idSat, false); 

       if (satToShow != null) 
        this.satController.glView.setSatelliteOrbitDisplayState(satToShow.Id, orbitButton.On); 
      } 
     } 

     // Create the cell at indexPath 
     public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) 
     { 
      string   cellName; 
      string   nibName; 
       cellName = "PROTO_CELL"; 
       nibName = "CellView"; 
      // Get the table cell which is described in the CellView.xib interface 
      var cell = tableView.DequeueReusableCell(cellName) as CellView; 

      if (cell == null) 
      { 
       cell = new CellView(); 
       var views = NSBundle.MainBundle.LoadNib(nibName, cell, null); 
       cell = Runtime.GetNSObject(views.ValueAt(0)) as CellView; 
      } 

      // Modify the cell with its own data 
      SatsList sat = (SatsList) satController.sats [indexPath.Row]; 

      CustomSwitch showButton = (CustomSwitch)cell.ViewWithTag(1); 
      UILabel   satName = (UILabel)cell.ViewWithTag(2); 
      UILabel   catalogNumber = (UILabel)cell.ViewWithTag(3); 
      CustomSwitch favoriteButton = (CustomSwitch)cell.ViewWithTag(4); 
      CustomSwitch orbitButton = (CustomSwitch)cell.ViewWithTag(5); 

      UIColor   lightgrey = new UIColor(0.85f, 0.85f, 0.85f, 1.0f); 
      tableView.BackgroundColor = lightgrey; 

      if (sat != null) 
      { 
       satName.Text = sat.satName; 
       catalogNumber.Text = string.Format("{0}", sat.catalogNumber); 
      } 
      else 
       System.Console.WriteLine("[ERROR] Satellite was not found for row " + indexPath.Row); 

      // Set switch state to on when the satellite is already being displayed 
      if (this.satController.glView.checkForSatelliteExistency(sat.Id)) 
      { 
       System.Console.WriteLine(sat.satName + "found"); 
       showButton.SetState(true, false); 
       Satellite sat3D = this.satController.glView.checkForSatelliteOrbit(sat.Id); 
       if (sat3D.displayOrbit()) 
        orbitButton.SetState(true, false); 
      } 
      else // force switch state to off when satellite is not displayed yet 
      { 
       showButton.SetState(false, false); 
       orbitButton.SetState(false, false); 
      } 
      favoriteButton.SetState(false, false); 

      // Bind changing state switches' events in order to display or hide the corresponding satellite 
      showButton.setData(sat.Id); 
      favoriteButton.setData(sat.Id); 
      orbitButton.setData(sat.Id); 
      if (!this.allocatedCells.Contains(indexPath.Row)) 
      { 
       showButton.ValueChanged += this.showButtonHandler; 
       orbitButton.ValueChanged += this.orbitButtonHandler; 
      } 
      this.allocatedCells.Add(indexPath.Row); 
      return cell; 
     } 

}

其實,上面的代碼的結果,是我能向上/向下滾動tableView沒有問題,我甚至可以得到「SHOW BUTTONHANDLER」這一行,直到我沒有點擊一個已經通過滾動離開屏幕的開關。 但是,當我點擊一個開關,是已在列表的頂部之前繪製和重新出現後,我滾動回到頂部,電池的部分上,然後我得到以下錯誤:

[7864:1507] -[UIControlTargetAction BridgeSelector]: unrecognized selector sent to instance 0x14462a70 

或以下堆棧跟蹤:

Stacktrace: 

    at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x0009f, 0xffffffff> 
    at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x00042] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:29 
    at App.Application.Main (string[]) [0x0001b] in App/Main.cs:24 
    at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00050, 0xffffffff> 

Native stacktrace: 

0 App      0x0009094c mono_handle_native_sigsegv + 284 
1 App      0x00005cd8 mono_sigsegv_signal_handler + 248 
2 libSystem.B.dylib     0x90d9c05b _sigtramp + 43 
3 ???         0xffffffff 0x0 + 4294967295 
4 UIKit        0x0222e55a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61 
5 UIKit        0x022d3b76 -[UIControl sendAction:to:forEvent:] + 66 
6 UIKit        0x022d403f -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 503 
7 UIKit        0x02425a6c -[_UISwitchInternalView _sendActions] + 121 
8 Foundation       0x0173786d __NSFireDelayedPerform + 389 
9 CoreFoundation      0x01195966 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22 
10 CoreFoundation      0x01195407 __CFRunLoopDoTimer + 551 
11 CoreFoundation      0x010f87c0 __CFRunLoopRun + 1888 
12 CoreFoundation      0x010f7db4 CFRunLoopRunSpecific + 212 
13 CoreFoundation      0x010f7ccb CFRunLoopRunInMode + 123 
14 GraphicsServices     0x04789879 GSEventRunModal + 207 
15 GraphicsServices     0x0478993e GSEventRun + 114 
16 UIKit        0x0222ba9b UIApplicationMain + 1175 
17 ???         0x0ebdde65 0x0 + 247324261 
18 ???         0x0ebdc550 0x0 + 247317840 
19 ???         0x0b7f7bac 0x0 + 192904108 
20 ???         0x0b7f7d86 0x0 + 192904582 
21 App      0x0000a042 mono_jit_runtime_invoke + 722 
22 App      0x00169f4e mono_runtime_invoke + 126 
23 App      0x0016e034 mono_runtime_exec_main + 420 
24 App      0x00173455 mono_runtime_run_main + 725 
25 App      0x00067245 mono_jit_exec + 149 
26 App      0x002116a5 main + 2837 
27 App      0x00003095 start + 53 
28 ???         0x00000004 0x0 + 4 

================================================================= 
Got a SIGSEGV while executing native code. This usually indicates 
a fatal error in the mono runtime or one of the native libraries 
used by your application. 
================================================================= 

所以,你有一個解決方案的想法?交換機的代理方法似乎沒有正確註冊,但我不知道什麼是錯的。因爲我也試過這個沒有

if (!this.allocatedCells.Contains(indexPath.Row)) 

行,爲了只註冊委託一次,但結果是一樣的。如果當單元格離開屏幕時試圖「取消註冊」委託,我是否需要刪除該單元?

我希望你有一個想法,不要猶豫,發表你的意見/建議/關於這一切的評論。

在此先感謝!

回答

1

好的,我發現問題與我的代碼,這是由於委託綁定到交換機。實際上,我忘記取消註冊正在離開屏幕的單元格的代表。 將一個ReuseableCell取出的事實不會刪除鏈接到該單元格內容的委託=>這會導致調用showButtonHandler(sender,args)方法,其中引用發生更改。

所以,我的代碼的解決方案是將最後部分更改爲:

// Bind changing state switches' events in order to display or hide the corresponding satellite 
      showButton.setData(sat.Id); 
      favoriteButton.setData(sat.Id); 
      orbitButton.setData(sat.Id); 

      showButton.ValueChanged -= this.showButtonHandler; 
      orbitButton.ValueChanged -= this.orbitButtonHandler; 
      showButton.ValueChanged += this.showButtonHandler; 
      orbitButton.ValueChanged += this.orbitButtonHandler; 
      return cell; 
     } 

對我來說,它不是必要的,即使在我的舊allocatedCells列表中登記的細胞。 重新使用單元格後,舊代表將從交換機中移除( - =),並用新的新引用替換(+ =)。

謝謝大家,不管。