【问题标题】:Button labels disappearing in XIB-backed view按钮标签在 XIB 支持的视图中消失
【发布时间】:2014-10-01 03:00:03
【问题描述】:

我对由 XIB 文件定义的视图有一个严重的问题。这是一个简单的数字输入板,带有 0-9 的按钮:

问题是在极少数情况下(如上面的屏幕截图所示),缺少按钮标签。它并不总是相同的标签(在上面的示例中,缺少“0”)。通常关闭视图并重新创建它可以解决问题。

XIB 文件的按钮附加到视图中的 UIButton 控件。视图是这样构造的:

@property (nonatomic,strong) IBOutlet UIButton *button0;
// etc...
@property (nonatomic,strong) IBOutlet UIButton *button9;

- (id)initWithFrame:(CGRect)frame
{
    self = [[UINib nibWithNibName:[[self class] description] bundle:nil]
                instantiateWithOwner:nil 
                options:nil
           ][0];

    if (self)
    {
        self.frame = frame;

        // ...
    }

    return self;
}

没有涉及控制器,我也不希望这样。

视图是用这样的代码创建的:

CustomView *view = [[CustomView alloc] initWithFrame:frame];

当问题发生时(不经常和随机),并且用户点击缺少标签的按钮,按钮的 titleLabel.text 属性为nil

- (IBAction) numberButtonPressed:(UIButton *)button
{
   NSLog("button label = %@",button.titleLabel.text);

   // output: button label = (null)
}

XIB 文件的 XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="5056" systemVersion="13C64" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
    <dependencies>
        <deployment defaultVersion="1536" identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view contentMode="scaleToFill" id="1" customClass="AmountEntryView">
            <rect key="frame" x="0.0" y="0.0" width="242" height="345"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="3" customClass="UIButton">
                    <rect key="frame" x="0.0" y="56" width="80" height="56"/>
                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                    <color key="backgroundColor" white="0.80112777219999998" alpha="1" colorSpace="calibratedWhite"/>
                    <fontDescription key="fontDescription" type="boldSystem" pointSize="40"/>
                    <state key="normal" title="7">
                        <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
                    </state>
                    <connections>
                        <action selector="numberButtonPressed:" destination="1" eventType="touchUpInside" id="142"/>
                    </connections>
                </button>

                <!-- ALL OTHER BUTTONS (omitted, as they are identical) -->

                <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="0.00" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="107">
                    <rect key="frame" x="0.0" y="0.0" width="242" height="56"/>
                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                    <color key="backgroundColor" white="0.91557459679999997" alpha="1" colorSpace="calibratedWhite"/>
                    <fontDescription key="fontDescription" type="boldSystem" pointSize="32"/>
                    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                    <nil key="highlightedColor"/>
                </label>
            </subviews>
            <color key="backgroundColor" white="0.72580645160000001" alpha="1" colorSpace="calibratedWhite"/>
            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
            <connections>
                <outlet property="button0" destination="86" id="108"/>
                <outlet property="button1" destination="58" id="109"/>
                <outlet property="button2" destination="60" id="110"/>
                <outlet property="button3" destination="59" id="111"/>
                <outlet property="button4" destination="30" id="112"/>
                <outlet property="button5" destination="32" id="113"/>
                <outlet property="button6" destination="31" id="114"/>
                <outlet property="button7" destination="3" id="115"/>
                <outlet property="button8" destination="19" id="116"/>
                <outlet property="button9" destination="8" id="117"/>
                <outlet property="buttonBack" destination="105" id="118"/>
                <outlet property="buttonDone" destination="106" id="119"/>
                <outlet property="buttonDot" destination="94" id="120"/>
                <outlet property="labelAmount" destination="107" id="133"/>
            </connections>
        </view>
    </objects>
</document>

我不知道为什么会出现此问题,并且我在此处或网络上的其他任何地方都找不到类似的报告。

【问题讨论】:

  • 您在代码中的任何地方都可以访问您的 button0,如果您可以分享您的代码,我可以更好地为您提供指导。
  • 调试日志中有任何内容?
  • 调试日志中没有任何内容,并且从不直接在代码中访问按钮。失去标签的按钮并不总是同一个按钮。
  • 您能以 XML 格式在此处发布您的 XIB 以供我们自己试用吗?
  • 标签是否丢失,因为没有文本,它的hidden 设置为true,或者它的框架为零?

标签: ios objective-c uiview xib nib


【解决方案1】:

检查这个 [self.view bringSubviewToFront:button0];

可能会对你有所帮助。

【讨论】:

    【解决方案2】:

    我真的不能说是什么导致了你描述的行为,但我想建议一种方法来尝试了解正在发生的事情,因为你不能分享你的项目。您可以尝试以下任何一种方法,所有这些方法都旨在找出text何时变为nil;我按复杂程度的顺序列出它们:

    1. button.titleLabel.text 属性添加一个KVO 观察者;如果这不起作用,

    2. UILabel setText: 方法与您自己的实现结合起来;如果这不起作用,

    3. 进入调试器并在 button.titleLabel.text 的内存位置设置监视(对于所有按钮,在创建时)。

    希望当text 变为nil 时,其中一种方法可以让您闯入您的应用程序,以便通过检查调用堆栈,您可以找出导致问题的原因。

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

      正如我在 cmets 中所说,您的问题真的很奇怪,但这不是我第一次需要从头开始重新创建 xib,导致一些奇怪的问题。
      曾经有人告诉我不要在 init 方法中交换 self,即使我认为这不能解决问题,我想给你两种不同的加载 xib 的方法。
      第一个:
      可能是您可以尝试仅更改一行代码的一种。假设在您的 xib 中,视图具有自定义类 CustomView 并且出口连接在这里并且文件所有者为零。尝试像这样加载:

      CustomView *view =[[UINib nibWithNibName:[NSStringFromClass(self.class) bundle:nil] instantiateWithOwner:nil options:nil][0];
      

      这将触发 xib 的加载过程,并获取其根对象,这与表格视图中的单元格原型可能使用的相同。如果您需要进行某种初始化,请在 -awakeFromNib 内部进行,因为不会调用 initWithFrame
      获取类名的正确方法不是 -description,因为它只是提供有关对象的信息,将来它可能会改变(不太可能),NSStringFromClass 只是将类名作为字符串获取。
      第二个:
      创建一个 xib,将文件的所有者设置为 CustomView 的实例,与文件的所有者建立连接,加载 xib 并将其添加为子视图。
      这是一个小类,我将其用作抽象类来创建使用 xib 的视图。

      @interface NibbedView : UIView
      @property (strong, nonatomic) IBOutlet UIView * nibView;
      
      - (instancetype) initWithNibName: (NSString*) nibViewName;
      - (instancetype) initWithFrame:(CGRect)frame  andNibName: (NSString*) nibViewName;
      
      - (void) loadNibWithName: (NSString*) nibName;
      
      
      @end
      

      和实施:

      @interface NibbedView ()
      @end
      
      @implementation NibbedView
      
      -(void) setContstraints {
          _nibView.translatesAutoresizingMaskIntoConstraints = NO;
          NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_nibView);
          [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_nibView]|" options:0 metrics: 0 views:viewsDictionary]];
          [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_nibView]|" options:0 metrics: 0 views:viewsDictionary]];
      }
      
      - (instancetype) initWithNibName: (NSString*) nibViewName{
          if (self = [self initWithFrame:CGRectZero]) {
              if (nibViewName) {
                  [self loadNibWithName:nibViewName];
              }
      
          }
          return self;
      }
      
      - (instancetype) initWithCoder:(NSCoder *)aDecoder {
          self = [super initWithCoder:aDecoder];
          if (self) {
              //
          }
          return self;
      }
      
      - (instancetype) initWithFrame:(CGRect)frame  andNibName: (NSString*) nibViewName{
          if (self = [self initWithFrame:frame]) {
              if (nibViewName) {
                  [self loadNibWithName:nibViewName];
              }
          }
          return self;
      }
      
      - (void) loadNibWithName: (NSString*) nibName {
          if (_nibView) {
              [_nibView removeFromSuperview];
          }
          else {
              [[NSBundle mainBundle] loadNibNamed: nibName owner: self options: nil];
              _nibView.frame = self.bounds;
              [self addSubview:_nibView];
              [self setContstraints];
          }
      
      }
      
      
      @end
      

      它使用自动布局使 xib 视图延伸到整个 CustomView 根视图。
      正如我所说,尝试在调试器中创建根视图的-recursiveDescription,即使未连接也可能位于层次结构中的某个位置。

      【讨论】:

        【解决方案4】:

        在 XIB 中,检查所有UIButtonsTitle 属性是否设置为Plain 而不是Attributed

        问题在于按钮或标签的text 与其attributedText 不同,如果两者都设置,则有时根本不会显示任何文本。尝试对此进行测试以查看是否有任何属性文本:

        - (IBAction)numberButtonPressed:(UIButton *)button {
            NSLog(@"%@", self.setButton.titleLabel.attributedText);
        }
        

        使用属性与纯文本的区别在于:

        [self.button0 setAttributedTitle:[[NSAttributedString alloc] initWithString:@"0"] forState:UIControlStateNormal];
        [self.button0 setTitle:@"0" forState:UIControlStateNormal];
        

        【讨论】:

        • 我会调查,但我仔细检查了 XIB 文件,所有 UIButton 都设置为纯文本
        【解决方案5】:

        我从未加载过或见过有人加载这样的 Nib。

        尝试使用更标准的[NSBundle.mainBundle loadNibNamed:owner:options:]

        【讨论】:

        • 您知道UINib nibWithNibName:bundle: 可能导致的任何问题(缺点)吗?
        • UINib 是在 iOS4(或 5)中引入的,主要区别在于 xib 是缓存的。使用该方法加载它完全没问题。
        • 我同意加载笔尖的方式很奇怪,但实际上并不能回答他的问题。
        • 我还是会试一试。使用这两种方法反序列化对象的方式可能存在一些差异。
        • 我会试试的
        【解决方案6】:

        设置标签时使用:

        [self.button0 setTitle:@"0" forState:UIControlStateNormal];
        

        不是:

        self.button0.titleLabel.text = @"0";
        

        此方法不会保留标题集,即旋转设备后标题消失等。

        其他可能的原因:

        • 减小 UIButton 中的字体大小。如果用户使用 设置使用大的动态字体大小,那么文本可能会变成 大到适合。

        • 在没有 XIB 的代码中设置 UIView。

        旁注: 您也可以通过标签引用按钮,然后您的代码将变得更简单,因为您不必单独连接每个按钮。

        【讨论】:

        • 我没有触摸代码中的标签文本,所以这不是问题。标签在 XIB 文件中设置。是什么让您认为我将 titleLabel.text 设置为代码中的字符串?
        • @PhilippeLeybaert 因为您要为每个按钮添加一个插座连接。如果你不设置标题,你用插座做什么?我添加了这个解释,因为我遇到了与您描述的相同的问题,这就是原因。
        • 我可以轻松删除插座(它们没有在代码中引用),但这会有什么不同呢?
        • 然后使用插座并在代码中设置按钮标签,如上所示。检查它是否不能解决问题,如果不能让我们知道。标题消失的另一个原因可能是您更改了 UIControlState (如果您没有将插座引用到按钮,这不太可能)。但是,请在对我投反对票之前检查一下。
        • @PhilippeLeybaert,我阅读了这个问题,上面写着“XIB 文件的按钮已附加到视图中的 UIButton 控件。”。因此,我假设代码中显示的插座用于为代码中的 UIButtons 设置标题或其他内容。你从来没有在你的问题中说这些插座是不必要的并且没有被使用。我们只能从给出的代码和文本中假设。但是解决您的问题的一种方法是在代码中构造 CustomView。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多