44107
スクロールビューの下にimageViewを配置してあります。

```

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var canvasView: UIImageView!
    var saveImageArray = [UIImage]()   //Undo/Redo用にUIImage保存用
    
    // タップされた座標にflowerを追加する(buttonをクリックした時の処理)
    let flower = UIImageView(image: UIImage(named: "flower"))
    flower.center = (sender as AnyObject).location(in: self.view)
    
```

**canvasViewの拡大を可能にしたい為､addSubView(flower)にしたら簡単にﾀｯﾌﾟ位置にimageの大きさで表示されかつ拡大出来たので良かったのですが､結果としてSubViewとcanvasViewでは格納場所が違うようで以降のundo処理が出来ない状態です｡  
描いた線,画像の拡大,縮小が出来てundo,redo処理が出来る様に考えています。  
現在の記述で描いた線,画像の拡大,縮小は出来るのだが,画像のredo,undoが出来ないです。  
(この処理の中には線の記述はないです)  
canvasView.addSubview(flower)

```

    //配列にcanvasView.imageを保存
    currentDrawNumber += 1
    saveImageArray.append(canvasView.image!) 
    
    //保存している直前のimageに置き換える (undoボタンをクリツクした時の処理)
    @IBAction func pressUndoButton(_ sender: Any) {
        if currentDrawNumber <= 0 {return}      
    
        self.canvasView.image = saveImageArray[currentDrawNumber - 1]   
        currentDrawNumber -= 1
    }
    
```

この処理で画像を書き換えられるはずなのですが、上手くいきません。  
教えて戴けませんか ?
CC BY-SA 4.0
2018-05-20T02:45:25.710
44099
2018-05-21T07:28:47.403
2018-05-21T07:28:47.403
26811
26811
question
swift swift4
絵を描くアプリで線はundo,redoできるのですがimageviewがundo,redoできません。
はじめまして。@OOPerさんが仰るとおり、クラス定義からクラス定義終了まで全てのコードが記述されていないので確実とは言えませんが、上のソースには

> タップされた座標にflowerを追加する(buttonをクリックした時の処理)

で、flowerという画像ファイルを`canvasView`に`addSubview`しています。  
つまり、`canvasView`にオーバーレイしたViewを作成し、そこにflowerという名前の画像を表示している様に見えます。

しかし、

> 配列にcanvasView.imageを保存

で`saveImageArray`にバックアップしている`canvasView.image`は、上に記述されたソース断片ではなにもセットしていないので、空のイメージの可能性が高く  
更に

> 保存している直前のimageに置き換える (undoボタンをクリツクした時の処理)

以降で保存された画像をセットし直しているのは、`canvasView`の`image`プロパティを操作しているように見えます。  
そうすると、

\---- flowerという最初にセットした画像 --------------------- = addされたSubview  
\----- バックアップした空のimageをUndoで再セットした画像 ----- = canvasView

と言うことが起きているのではないでしょうか  
このため、undoボタンをクリックしたときの処理は実際に行われていても、  
addされたSubviewの下に隠れて見えていない事が予想されます。  
なので、

a. タップされた座標に〜 の部分で、`addSubview`せず、`canvasView`の`image`に画像をセットする

```

    let flower = UIImage(named: "flower")
    // センタリング処理省略
    canvasView.image = flower
    
```

b. Undoアクション
の部分で、`addSubview`した`view`の`image`に画像をセットする（バックアップするイメージの取得元も`addSubview`した`view`の`image`プロパティにする）

```

    // nはaddSubviewしたflowerのsubViewsから取得される順番
    self.canvasView.subViews[n].image = saveImageArray[currentDrawNumber - 1] 
    
```

または

```

    // flowerが例示されたソースの通り、クラスのメンバー変数であれば
    // イメージのバックアップも書き戻しもflowerに対して行えばよい
        // 配列にcanvasView.imageを保存の部分
    saveImageArray.append(flower.image!)
        // 保存している直前のimageに置き換えるの部分
    flower.image = saveImageArray[currentDrawNumber - 1]
    
```

ただし、この場合、`let
flower`は適切な変数名ではないので、クラス内全体を通して`flower`こそが実質的にキャンバスであると言うことが解る変数名に書き替えた方が間違いが少なくなると思います

以上より、a,bで例示したどちらか片方に統一すれば良いような気がします。  
bの例示は2つ示しましたが、どちらか片方だけが必要で、両方の修正を行うと、また挙動がわからなくなります。

ただしbの解決方法は、「ではIBOUtletで宣言しているcanvasViewというImageViewは何のために存在しているか？」がわからない、必要のないオブジェクトになってしまうので、勝手な予測ながら「よくわからないけど、こうすれば動いた」以上の意味は無いのでは無いかと思います。  
このため、a.で示した、IBOutlet宣言したcanvasViewに極力余計なViewをaddしない方針でプログラムの修正をし、どうしても質問に記述されていない部分が理由で`addSubview`する必要でない限り、b.の方針でプログラムを修正すべきではない様に思えます。
CC BY-SA 4.0
2018-05-20T12:19:07.587
44107
2018-05-21T05:39:42.700
2018-05-21T05:39:42.700
14745
14745
44099
answer