在没有 MonoTouch 托管类的情况下获取 Objective-C 类名

Posted

技术标签:

【中文标题】在没有 MonoTouch 托管类的情况下获取 Objective-C 类名【英文标题】:Getting an Objective-C class name without having a MonoTouch managed class 【发布时间】:2012-07-24 05:11:53 【问题描述】:

我终其一生都想不出如何将它翻译成 MonoTouch。有接盘侠吗?

for(UIView* view in cell.subviews)

    if([[[view class] description] isEqualToString:@"UITableViewCellReorderControl"])
    
    

让我难过的主要是视图类描述......

【问题讨论】:

【参考方案1】:

我目前没有使用 Monotouch,但您不应该只检查子视图的托管类型吗?

   foreach (UIView view in cell.subviews)
   
     if (view is UITableViewCellReorderControl) 
   

【讨论】:

是的,原来的 direct 主要是在做:view.GetType ().ToString () 其中[view class] 返回类型,description 返回名称(description 也被使用,由默认为NSObject.ToString()。然而,来自@Monoman 的adapted 翻译更能代表这意味着什么。 如果 System.Linq 可用,您可以进一步缩写:foreach(var view in cell.subViews.OfType<UITableViewCellReorderControl>()) foreach (UIView subView in cell.Subviews) if(subView is UITableViewCellReorderControl) 抛出错误:错误 CS0246:找不到类型或命名空间名称“UITableViewCellReorderControl”。您是否缺少 using 指令或程序集引用? (CS0246) 这在这种情况下不起作用,因为UITableViewCellReorderControl 是一个深层的UIKit 内部。【参考方案2】:

Objective-C Class 的处理大部分隐藏在 MonoTouch 提供的 API 中。主要是 System.Typedescription 主要是 ToString - 但这不会显示一些内部结构。

您可以尝试以下几件事(从简单到复杂):

view 实例上调用ToString可能包括原始类名(作为描述的一部分) - 但它与调用class 本身的description 不同.

 foreach (UIView view in cell.Subviews) 
    if (view.ToString ().Contains ("UITableViewCellReorderControl")) 
    
 

接下来尝试查看Class 上的Name 是否与description 相同。

foreach (UIView view in cell.Subviews) 
   MonoTouch.ObjCRuntime.Class c = new MonoTouch.ObjCRuntime.Class (view.GetType ());
   if (c.Name == "UITableViewCellReorderControl") 
   

最后真正调用Class 实例上的description 选择器。类似(未尝试):

MonoTouch.ObjCRuntime.Selector description = new MonoTouch.ObjCRuntime.Selector ("description");
foreach (UIView view in cell.Subviews) 
   MonoTouch.ObjCRuntime.Class c = new MonoTouch.ObjCRuntime.Class (view.GetType ());
   var name = NSString.FromHandle (MonoTouch.ObjCRuntime.Messaging.IntPtr_objc_msgSend (c.Handle, description.Handle));
   if (name == "UITableViewCellReorderControl") 
   

【讨论】:

我修复并测试了你的第三个。这些都没有捕获 OP 案例中的类型。我添加了一个答案,其中包含我测试过的几个实现。 效果很好!但是现在我必须弄清楚在哪里实现,以便表格中的单元格获得 ReorderControl 的新位置。如果我把它放在 WillDisplay 中,一切看起来都很好,直到我实际移动一个单元格。然后所有移动的单元格恢复到原始控件位置。关于移动后哪个方法会更新设置的任何想法?【参考方案3】:

一般来说,@Monoman's is solution 是查找特定类实例的正确方法,即使是在 MonoTouch 程序中查找 CocoaTouch 类时也是如此。

但是,有时您会发现有一个内部 CocoaTouch 类未在 MonoTouch 中公开(甚至在 ios 平台标头中)。在这种情况下,您将不得不求助于tricks like @poupou is doing。

不幸的是,他的答案在这里也行不通view.GetType() 正在返回每个 Subview 实现的最衍生的 MonoTouch 类型,然后是 ToString()Class.Name 甚至 @selector("description") 每个都在错误的类型上操作并给出过于通用的答案(“UIView " 在这种情况下)。

为了完成这项工作,您必须比@poupou 建议的更深入一层

// ** using MonoTouch.ObjCRuntime; **

private string GetClassName (IntPtr obj) 
    Selector description = new Selector ("description");
    Selector cls = new Selector ("class");
    IntPtr viewcls = Messaging.IntPtr_objc_msgSend (obj, cls.Handle);
    var name = NSString.FromHandle (Messaging.IntPtr_objc_msgSend (viewcls, description.Handle));
    return name;

这里有一个替代方案,它不是更复杂(甚至可能更少?),但适用于任何 Objective-C 类,而不仅仅是那些响应NSObjectdescription 消息的类:

// ** using System.Runtime.InteropServices; **

[DllImport ("/usr/lib/libobjc.dylib")]
private static extern IntPtr object_getClassName (IntPtr obj);

private string GetClassName (IntPtr obj) 
    return Marshal.PtrToStringAuto(object_getClassName(obj));

MonoTouch 还没有为object_getClassName() 提供导入,这确实令人惊讶,也有点遗憾。

您可以使用其中任何一种:

foreach (UIView view in cell.Subviews) 
    if (GetClassName(view.Handle) == "UITableViewCellReorderControl") 
    

大胖子免责声明:几乎任何时候您使用这些技巧时,您都依赖于 Apple 保留更改权利的 CocoaTouch 实现细节。经验法则:如果您可以使用 @Monoman 的解决方案做您想做的事,那么您可能是安全的。否则,您将自己处理事情。

【讨论】:

【参考方案4】:

这对我有用:

foreach(var subview in this.ContentView.Superview.Subviews)

    if(subview.Class.Name.EndsWith("UITableViewCellReorderControl"))
    
    

【讨论】:

以上是关于在没有 MonoTouch 托管类的情况下获取 Objective-C 类名的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有继承方法的情况下获取类的公共方法?

如何在模拟器中为 MonoTouch 应用程序生成 .dSYM?

Monotouch对话框多行元素高度没有增长

在 MonoTouch MonoDevelop 中重命名控制器类

在没有原始文件系统权限的情况下获取磁盘扇区大小

如何在不导入类的情况下获取类的方法