zoukankan      html  css  js  c++  java
  • File’s Owner探究

        首先粘上iOS开发文档对File's Owner的解释:

    One of the most important objects in a nib file is the File’s Owner object. Unlike interface objects, the File’s Owner object is a placeholder object that is  not created when the nib file is loaded. Instead, you create this object in your code and pass it to the nib-loading code. The reason this object is so        important is that it is the main link between your application code and the contents of the nib file. More specifically, it is the controller object that is   responsible for the contents of the nib file.
    
    In Xcode, you can create connections between the File’s Owner and the other interface objects in your nib file. When you load the nib file, the nib-loading    code recreates these connections using the replacement object you specify. This allows your object to reference objects in the nib file and receive messages   from the interface objects automatically.

    从这段描述中可以得到以下信息:

    1.File's Owner是一个Placeholder对象,需要手动创建一个File's Owner对象,在载入Nib文件时传入该参数。

    2.更具体地讲,File's Owner通常是controller对象。

    3.可以在File's Owner与Nib文件创建connections。

        根据上面抽取的信息,感觉已经足够全面地描述一个File's Owner对象,首先描述了是什么,其次讲了何时需要何时生成,更是给出了一个具体的例子即Controller,最后还讲了在File's Owner与Nib文件可以执行的操作。但是,读者可能会有这样的疑问:File's Owner可以设定非Controller对象吗?载入Nib文件时一定要指定File's Owner吗?第一个问题比较容易回答,答案是肯定的,创建一个新的Nib文件时默认的File's Owner是NSObject对象,所以是可以的。你甚至可以将File's Owner设为nil,前提是不需要在File's Owner与Nib文件之间建立connections。第二个问题就是我们下面研究的重点。

        上图展示了File's Owner与loadNibNamed中的owner参数的一些取值的组合,当然这里没有涵盖全部,但是已经足够支持我们的结论。从图中可以明显看出,只有当File's Owner为controller,且与Nib文件之间存在connections时,loadNibNamed中的owner参数必须为File's Owner这个对象,其他情况都会导致运行时崩溃,具体的形式是丢出一个异常。当File's Owner为Non Controller时,loadNibNamed中的owner参数对传入的值是不敏感的,即设置任何的值都可以正常工作。

        这是为什么呢?这得从Nib文件的构成来描述,实际上Nib文件是一个Xml文件,所以咱们就可以从这里入手分析。这里分两种情况分析Nib文件:File's Owner为Controller With Connections和File's Owner为Non Controller时。

        这里,我们写了一个Demo研究这个问题,定义了一个Custom Class TextView,其包含两个subView:testButton和testLabel,其类型分别为UIButton和UILabel,TextView对应一个TextView.xib文件,用来描述该TextView。

        File's Owner为Controller With Connections

            <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MainViewController">
                <connections>
                    <outlet property="testButton" destination="pOG-Rg-y6T" id="Lwm-Vc-rbU"/>
                    <outlet property="testLabel" destination="bwx-rO-0XM" id="5FI-sW-N7N"/>
                </connections>
            </placeholder>
            <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
            <view contentMode="scaleToFill" id="1" customClass="TextView">
                <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                <subviews>
                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bwx-rO-0XM">
                        <rect key="frame" x="139" y="231" width="42" height="21"/>
                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                        <nil key="highlightedColor"/>
                    </label>
                    <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pOG-Rg-y6T">
                        <rect key="frame" x="124" y="313" width="73" height="44"/>
                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <state key="normal" title="Button">
                            <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
                        </state>
                        <connections>
                            <action selector="buttonClicked:" destination="-1" eventType="touchUpInside" id="clI-Ad-DZr"/>
                        </connections>
                    </button>
                </subviews>
                <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
                <simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/>
                <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
            </view>

         connections已经使用下划线标出,看到outlet connection的形式是这样的:<outlet property="testButton" destination="pOG-Rg-y6T" id="Lwm-Vc-rbU"/>,property表示建立连接时被关系的属性名,id标示该outlet。在上面的代码中使用destination的值pOG-Rg-y6T搜索,发现subView Button的id也为pOG-Rg-y6T,可知destination表示建立连接时用来设置property的对象。action connection的形式如下:<action selector="buttonClicked:" destination="-1" eventType="touchUpInside" id="clI-Ad-DZr"/>,这里重点介绍destination,在代码中搜索destination的值-1,发现File's Owner的id为-1。可知,action的destination的属性跟outlet的destination并不一样,action中的destination对应于UIControl中的addTarget:action:forControlEvents:的target参数。而outlet中的destination对应于NSKeyValueCoding Protocol的setValue:forKey:中的value。

            <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MainViewController">
                <connections>
                    <outlet property="testButton" destination="pOG-Rg-y6T" id="Lwm-Vc-rbU"/>
                    <outlet property="testLabel" destination="bwx-rO-0XM" id="5FI-sW-N7N"/>
                </connections>
            </placeholder>

        另外,从上面代码中可以看出outlet connections在IBFilesOwner这个placeholder下面,其id为-1,据个人推断,负值id表示该对象需从外部传入,无法从Nib文件中生成。所以,当Nib文件与Controller之间存在connections,必须传入合适的owner值,否则会在setValue:forKey时找不到对应于key的propery而丢出异常,形式通常如下:Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0xa26ba00> setValue:forUndefinedKey:]。

        File's Owner为Non Controller

           <view contentMode="scaleToFill" id="1" customClass="TextView">
                <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                <subviews>
                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bwx-rO-0XM">
                        <rect key="frame" x="139" y="231" width="42" height="21"/>
                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                        <nil key="highlightedColor"/>
                    </label>
                    <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pOG-Rg-y6T">
                        <rect key="frame" x="124" y="313" width="73" height="44"/>
                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <state key="normal" title="Button">
                            <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
                        </state>
                        <connections>
                            <action selector="buttonCliked:" destination="1" eventType="touchUpInside" id="OWy-DA-Gnl"/>
                        </connections>
                    </button>
                </subviews>
                <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
                <simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/>
                <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
                <connections>
                    <outlet property="testButton" destination="pOG-Rq-y6T" id="8dI-KM-kpl"/>
                    <outlet property="testLabel" destination="bwx-rO-0XM" id="AdC-8e-c0u"/>
                </connections>
            </view>

        下划线标出的代码为conenctions,outlet connections在view下面,明显区别于File's Owner为Controller With Connections。出现这种情况是因为outlet connections建立在TextView和Nib文件之间,而在File's Owner为Controller With Connections时,connections则建立在File's Owner与Nib文件之间,所以放置的位置也不同。从上面两种不同的outlet connections放置位置,当与某个类建立outlet连接时,该outlet connections会放置在该类生成的对象的描述下面。同时,从上面的代码中可知,action connection的destination值为1,在代码中搜索发现TextView的id为1,可知该action connection建立在TextView与Nib文件之间,这也与我们的设计相符。通过对该Nib文件的分析,可知owner参数是否传递有效的参数并不重要,因为该Nib文件已经包含了足够的信息,在该Nib文件的载入过程中可以得到足够的信息建立连接。结合该Demo来讲,当构建outlets时,由TextView定义的view已经实例化完成,该对象有两个property:testButton和testLabel,因此,不用传入有效的owner值也可以完成该对象的初始化。

        综上所述,可知File's Owner并不是必须的,loadNibNamed:owner:options:中的owner参数也不是必须的。只有当File's Owner与Nib文件之间存在connections,才需要指定Files's Owner以及设定有效的owner参数,其他情况都不需要特别的设定File's Owner,以及loadNibNamed:owner:options:中的owner参数。

        个人更为推荐File's Owner为Non Controller的Nib文件设计,这样可以方便地复用该Nib文件,不跟特定的Controller绑定,也更符合模块化设计准则,可以尽量地隐藏实现细节,好处多多。对于有action connection需求的,可以通过代码addTarget:action:forControlEvents:来实现,方便代码的管理,在Nib实现和代码实现之间取得平衡。

  • 相关阅读:
    java多线程的简单demo
    对RedisTemplate接口二次封装成自定义工具接口
    开发中常遇到的linux系统配置操作整理
    Mybatis传递参数的三种方式
    创建Springmvc项目时,特殊拦截器失效情况的原因及解决办法
    Quartz的Hello world
    JAVA 中数组的几种排序方法
    二叉树的遍历
    eclipse 修改中英文显示
    Spring加载配置文件的三种方式
  • 原文地址:https://www.cnblogs.com/CoderPlace/p/3502340.html
Copyright © 2011-2022 走看看