22289


Swiftにおいて、CGRectを変更する場合は

[code]

    let view = UIView()
    view.frame = CGRect(x:0.0, y:100.0, width:200.0, height:200.0)
    //widthを変更したい
    view.frame = CGRect(x:0.0, y:100.0, width:300.0, height:200.0)
    
[/code]

と、このようにwidthだけ変更したい場合でもCGRectの長い文をツラツラ書いています。

このようにCGRectを一箇所だけ変更したい場合において、何か上手な書き方ってありますか？

また、どういったメリット、デメリットがあって

[code]

    view.frame.width = 300.0
    
[/code]

という書き方ができないように、CGRectのプロパティがreadonlyにしてあるのかも  
教えていただけると参考になります。


CC BY-SA 3.0
2016-02-19T12:34:00.087
22273
2016-02-19T23:14:53.667
13404
question
swift
CGRectの上手な書き方

[code]

    let view = UIView()    
    view.frame.size.width = 300.0
    
[/code]

のように書くのはどうでしょうか？


CC BY-SA 3.0
2016-02-19T15:32:45.997
22278
2016-02-19T15:32:45.997
5519
22273
answer


`CGRect`という構造体に対する誤解があるように見えます。構造体`CGRect`はそもそもなにかを調べることから始めましょう。  
Xcodeの索引能力は強力です。それを使わない手はありません。Xcodeのエディタに`CGRect`と入力します。その上にマウスカーソルを当て、Optionキーを押しながらクリックすると、ミニリファレンスが現れます。（下図）  
[![画像の説明をここに入力](https://i.stack.imgur.com/lxcBq.png)](https://i.stack.imgur.com/lxcBq.png)

ミニリファレンスの一番下の行「Reference」をクリックすると、フルリファレンスが開きます。そこには、`CGRect`の定義が書かれています。

[code]

    struct CGRect {
        var origin: CGPoint
        var size: CGSize
    
        init()
        init(origin origin: CGPoint, size size: CGSize)
    }
    
[/code]

`CGRect`は、`CGPoint`と`CGSize`をメンバーとする構造体であることがわかります。  
質問者さんの予想と違っていたのではありませんか？質問者さんは、このように予想していらっしゃったのでは？

[code]

    struct CGRect {
        var x: CGFloat
        var y: CGFloat
        var width: CGFloat
        var height: CGFloat
    }
    
[/code]

予想どおりなら、`view.frame.width =
300.0`という書き方ができるはずですが、予想どおりではないので、そうは書けません。`width`は`CGRect`のメンバーではないんですね。けっして、`CGRect`のプロパティ（メンバー）がRead
Onlyだからではありません。  
`width`は`CGSize`のメンバーです。

[code]

    view.frame.size.width = 300.0
    
[/code]

これなら書けます。  
「いちいち`size`を書くのはめんどう」と思われるかもしれません。その場合は、`CGRect`を拡張してあげましょう。

[code]

    extension CGRect {
        var width: CGFloat {
            get {
                return self.size.width
            }
            set {
                self.size.width = newValue
            }
        }
    }
    
[/code]

こう拡張すると、`view.frame.width = 300.0`が可能になります。


CC BY-SA 3.0
2016-02-19T23:04:19.787
22289
2016-02-19T23:04:19.787
7362
22273
answer


> どういったメリット、デメリットがあって
[code]

>     view.frame.width = 300.0
>  
[/code]

>
> という書き方ができないように、CGRectのプロパティがreadonlyにしてあるのか

の部分ですが、メリット・デメリットというよりはSwiftからFoundationのデータ型をimportする部分を設計した人のデザインセンスの問題ということになりそうです。

CGRectはObjective-C側で次のように宣言されています。

[code]

    struct CGRect {
        CGPoint origin;
        CGSize size;
    };
    typedef struct CGRect CGRect;
    
[/code]

ご覧のようにCGRectにはwidthというプロパティ(Objective-Cのstructならメンバーというべきでしょうか)はありません。  
Objective-
Cでは、structにプロパティやメソッドを追加することはできませんでしたから、CGRectのwidthにアクセスする場合には、素直にメンバー階層をたどるか、

[code]

    CGRect rect = CGRectZero;
    CGFloat width = rect.size.width;
    
[/code]

あるいはアクセス関数を用いるしかありませんでした。

[code]

    CGFloat width = CGRectGetWidth(rect);
    
[/code]

これらのアクセス関数にはいろいろあります(CGGetMinX()やらCGRectIsNull()やら...)が、Swiftでそれらのimport部分の設計を担当した人は、それらのアクセス関数をextension内でプロパティとしてもアクセスできるようにしてしまったようです。  
(Cmd-Clickで表示されるヘッダにおけるCGRectのextension部分)

[code]

    extension CGRect {
        //...
        public var width: CGFloat { get }
        //...
        public var minX: CGFloat { get }
        //...
        public var isNull: Bool { get }
        //...
    }
    
[/code]

実際[オープンソース化されたSwiftのソース](https://github.com/apple/swift/blob/master/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift)を見るとそれらのプロパティは次のような感じで定義されています。

[code]

      var width:  CGFloat {
        @_transparent // @fragile
        get { return CGRectGetWidth(self) }
      }
      //...
      var minX:   CGFloat {
        @_transparent // @fragile
        get { return CGRectGetMinX(self) }
      }
    
[/code]

(`@_transparent`とかはライブラリの作者が内部的に使うものなので無視してください。)  
したがって、「CGRectのwidthプロパティは、あくまでもCGRectGetWidth()を呼ぶためのショートカットである」と言うふうに理解すべきなのでしょう。(CGRectSetWidth()なんて関数はなかったので、setterは存在しない。)  
ただ、widthやheightなど、矛盾なくsetterを定義できるものについて、あえてそうはしなかったのは、「設計者のデザインセンス」としか言えないように思います。


CC BY-SA 3.0
2016-02-19T23:14:53.667
22290
2016-02-19T23:14:53.667
13972
22273
answer