web-dev-qa-db-ja.com

myView.frame.Origin.x =値;動作しません-しかし、なぜですか?

私はこれを使用できないことを知っています:

myView.frame.Origin.x = 25.0;

代わりにこれを使用する必要があります。

CGRect myFrame = myView.frame;
myFrame.Origin.x = 25.0;
myView.frame = myFrame;

そして、私はいつもそれをやっています、しかし私はなぜ私がそれをそのようにしなければならないのか分かりません。私の理解のギャップを埋めたいと思います。誰かが説明できますか?

現在、Xcodeは「表現を割り当てられません」を提供します。少し前に、コンパイルエラー「割り当ての左側のオペランドとして左辺値が必要です」が発生しました。

31
Allisone

これが機能しない理由は、2つの構文が混在しているためです。
最初に「。」があります。アクセサ関数(Objective-C機能)を呼び出すためのショートカットとして。そう

  • a.bは[getB]になります。
  • a.b = 5は[asetB:5]になります。

そして、そこに「。」があります。直接構造体メンバーアクセスとして(純粋なC)。そう

  • a.bは実際にはa.bです。
  • a.bは実際にはa.b = 5です。

このようにset-value-caseでこれを組み合わせると、機能しません。
なぜなら...あなたが電話できれば

myView.frame.Origin.x = 25.0;
  • 「myView.frame」の部分は[myViewgetFrame]と等しく、コピーされたCGRectフレーム(C構造体)を取得します。

  • 「myView.frame.Origin」は、コピーされたCGRectのCGPointオリジン(構造体でもあります)を提供します

  • 「myView.frame.Origin.x = 25.0」は、原点のCGFloat xを提供します。次に、何かを割り当てたいと思いますが、ここで問題が発生します...

構造体の構造体の変数を設定しようとしましたが、これは問題ありませんが、UIViewから構造体へのポインターがないため、代わりにコピーされます。したがって、コピーしてから設定すると、setアクションがUIViewへの最初の取得を通じて何らかの形で転送されることが期待されますが、これは機能しません。

もちろん、なぜAppleがショートカットを作成しただけではないのか、コピーしたフレームが自動追加されたsetFrame呼び出しに自動的に再注入されるのか、不思議に思うかもしれません。それはどうですか。

したがって、フレームへのポインタを取得すれば機能しますが、そうではなく、代わりにコピーされた構造体を取得することを忘れないでください。
だから、もしあなたがmyView.frame.Origin.x = 25.0動作するには、呼び出しが自動的に何らかの種類に変換されることを間接的に期待します
[myView setFrame:[myView getFrame:frame].Origin.x = 25.0]
まあ、これは間違っているように見えることを認めることができると思います。

また、CGRectフレームへの直接ポインターを取得し、そのポインターを介して何かを変更した場合、UIViewは、サイズが変更され、それ自体を更新する必要があることをどのように認識しますか?一方、[myView setFrame:newFrame]呼び出しが行われた場合、UIViewは必要なすべての再調整を実行できます。

18
Allisone

ここで使用されている2つの異なるドット構文があります。それらは同じように見えますが、操作対象とそれを使用して実行されている内容に応じて、異なる動作をします。

  • 最初のmyView.frameは、[myView frame]の省略形であり、CGRect struct 値によるを返すメソッド呼び出しです。
  • myFrame.Origin.xは、従来のC方式で通常の構造体メンバーにアクセスしています。
  • 2番目のmyView.frameも省略形ですが、ステートメントは割り当てであるため、別のメソッド[myView setFrame:myFrame]を呼び出すことになります。

単一行の上の例では、rectのコピーを取得し、そのxを設定しますが、ビューにコピーして戻すことは決してありません。メソッド呼び出しを明示的に区別する必要があります。ドットシンタックスシュガーはそれらを単一の呼び出しに魔法することはできません。

40
walkytalky

CGRectは構造体であり、標準Cのものです。CGRectnot Objective Cオブジェクトであるため、そのメンバーの1つに割り当てると、セッターメソッドが呼び出されます。セッターメソッドが呼び出されないと、UIKitは何かが変更されたことを知ることができないため、画面表示を更新できません。

編集:指摘されているように、割り当ては構造体のコピーになります。

2
Emil

データを直接操作する場合、アクセサーは呼び出されないため、UIはそれ自体を更新できません。または、変更について知りたい他のコンポーネントに通知することもできません。

編集:walkytalkyが指摘しているように、データのコピーを取得するため、データを変更しても元のデータには影響しません。次の例はこれを示しています。

UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(50,50,100,100)];
NSLog(@"%f", aView.frame.Origin.x); // will give 50
aView.frame.Origin.x = 17;  // operates on a copy of the rect only
NSLog(@"%f", aView.frame.Origin.x);  // will still give 50
1
Eiko