

構成としては、

  * 親 `UIViewController`
  * 子 `UIImageView`
  * 孫 `UIWebView` ※複数

のような作りで、子を背景画像として、子に孫を複数 `addSubView` して、結果として小さい `UIWebView`
が背景画像の上にいくつか乗っているような見た目となっています。

孫のいずれかをタップした際に、孫を全画面表示させたい為、タップされた孫の frame を全画面サイズに変更し、親に直接 `addSubView` して
_親→子→孫_ だったものを _親→孫_ のように付け替えています。 iOS7 まで (正確には Xcode 4.x )
で開発していた際にはこれで上手くいっていたのですが、iOS8 に対応させる為に、 Xcode 6 にて表示のズレを xib
ファイルで修正して動作確認したところ、孫を直接親に `addSubView` するタイミングで対象の `UIWebView`
が表示されず、消えてしまうようになりました。

親に対して、新規でインスタンスを作った別の `UIWebView` を `addSubView`
するとちゃんと表示されるので、付け替えを行うとメモリから解放されてしまったりしているのでしょうか？？ `addSubView`
の直後に対象オブジェクトをログ出力してみると `nil` とはなっていないので解放されてるわけではないのでしょうか・・・

対象の `UIWebView` は `IBOutlet` で `(nonatomic, retain)` の `property` として宣言しています。

どなたかお知恵をお貸し頂けませんでしょうか (>_<)  
宜しくお願い致します。

-----追記-----  
関連のありそうな箇所のコードを以下に載せます。  
GestureWindow でダブルタップを検知したら BaseController の doubleTapedWebView
を呼び出す作りとなっております。

又、親への付け替えをせずに( addSubView をせずに)、この中で一番上に表示させる事で要件を満たそうと試みたところ、不可解な動きとなりました。

  * 初回の最大化時→他の孫の後ろに隠れた状態( bringSubviewToFront が効いていない？)で、表示位置も frame の position に0,0を指定しているにも関わらず元の位置から動いていない
  * ２回目以降の最大化時→一番上に表示され期待通り最大化表示となる

２回目以降には一度最大化からオリジナルサイズへ戻す処理の中で addSubView しているのでそもそも bringSubviewToFront
が効いていないという事なのかもしれませんが。。  
こちらの原因も思い当たる方がいらっしゃればお教え頂けると助かります。

宜しくお願い致します。

[code]

     BaseController.h
    #import 
    #import "ThumbnailImageView.h"
    #import "MainImageView.h"
    #import "GestureWindow.h"
    #import "GDataXMLNode.h"
    
    @interface UIWebView (privateAPI)
    - (NSString *)recursiveDescription;
    @end
    
    @interface BaseController : UIViewController 
    {
        IBOutlet UIImageView* _base;
        IBOutlet UIWebView* _info;
        IBOutlet UIWebView* _corp;
        IBOutlet UIWebView* _movie;
    }
    @property (nonatomic, retain) IBOutlet UIWebView *_info;
    @property (nonatomic, retain) IBOutlet UIWebView *_corp;
    @property (nonatomic, retain) IBOutlet UIWebView *_movie;
    @property (nonatomic, retain) IBOutlet UIImageView *_base;
    
    @end
    
[/code]

[code]

     BaseController.m
    #import "BaseController.h"
    #import "UIImage+Extras.h"
    #import "ThumbnailImageView.h"
    #import "GestureWindow.h"
    #import 
    #import "NSBundle+MyStrings.h"
    
    @interface BaseController ()
    
    @end
    
    
    @implementation BaseController
    @synthesize _corp;//孫のUIWebViewプロパティ
    @synthesize _info;//孫のUIWebViewプロパティ
    @synthesize _movie;//孫のUIWebViewプロパティ
    @synthesize _base;//子のUIImageViewプロパティ
    
    - (void)viewDidLoad
    {
        gWindow = (GestureWindow*)[[UIApplication sharedApplication].windows
                                                  objectAtIndex:0];
        gWindow.gDelegate = self;
        NSMutableArray* webArray = [NSMutableArray array];
        [webArray addObject:_info];
        [webArray addObject:_corp];
        [webArray addObject:_movie];
    
        gWindow.webViewArray = webArray;
    }
    
    -(void) doubleTapedWebView:(UIWebView *)webView
    {
        NSLog(@"doubleTapedWebView start:%p",webView);
        UIScreen *screen = [UIScreen mainScreen];
        if([self isInitBeforeRect]){
            //オリジナル→最大化
            beforeRect = webView.frame;
            [webView.scrollView setZoomScale:maxScale animated:YES];
            webView.frame = CGRectMake(
                                      0
                                      ,0
                                      ,screen.bounds.size.width
                                      ,screen.bounds.size.height
                                      );
    
            [webView.layer setCornerRadius:0];
            [self.view addSubview:webView];
    //        [_base bringSubviewToFront:webView];//試しに親への直接付け替えをせずに子の中で一番上に表示させる
        }else{
            //最大化→オリジナル
            [webView.layer setCornerRadius:10];
            isAutoZoomed = NO;
            [webView.scrollView setZoomScale:minScale animated:YES];
            webView.frame = beforeRect;
            [self initBeforeRect];
            [_base addSubview:webView];
       }
    }
    @end
    
[/code]

[code]

     GestureWindow.h
    @protocol GestureWindowDelegate
    
    - (void) doubleTapedWebView:(UIWebView*)webView;
    
    @end
    
    #import 
    
    @interface GestureWindow : UIWindow{
        NSMutableArray* webViewArray;
        id gDelegate;
        NSTimeInterval lastEventTime;
        NSTimeInterval currentEventTime;
    }
    @property (nonatomic, retain) id gDelegate;
    @property (nonatomic, retain) NSMutableArray* webViewArray;
    @property (nonatomic) NSTimeInterval lastEventTime;
    @property (nonatomic) NSTimeInterval currentEventTime;
    
    @end
    
[/code]

[code]

     GestureWindow.m
    @implementation GestureWindow
    
    
    @synthesize gDelegate,webViewArray,lastEventTime,currentEventTime;
    
    - (void)sendEvent:(UIEvent *)event {
        currentEventTime = event.timestamp;
        [super sendEvent:event];
        NSSet *touches = [event allTouches];
        //マルチタッチは禁止
        if (touches.count != 1) {  
            return;  
        }
    
        UITouch *touch = touches.anyObject;
        int tcCnt = [touch tapCount];
    
        //ダブルタップでない場合は終了
        if(tcCnt !=2){
            return;
        }
        // 指定のUIWebViewへのタッチか
        for(UIWebView *uw in webViewArray){
            if([touch.view isDescendantOfView:uw]){
                if((currentEventTime - lastEventTime) ＜ 0.7){
                    break;
                }
                lastEventTime = currentEventTime;
    
                [gDelegate doubleTapedWebView:uw];
                NSLog(@"call doubleTapedWebView:%p",uw);
                break;
            }
        }
    }
    @end
    
[/code]


CC BY-SA 3.0
2015-02-10T09:21:42.843
6255
2015-02-12T02:39:25.940
2015-02-12T02:39:25.940
8200
8200
question
ios ios8
UIWebView の親を動的に変更したい


手元で以下のコードで試してみたのですが、再現しませんでした。  
そのため、

> 親→子→孫 だったものを 親→孫 のように付け替えています。

ではなく別の原因によって動作が変わっているものだと思われます。

[code]

    @interface MainViewController ()
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;    // xib で配置
    @property (nonatomic, strong) NSMutableArray *webViews;
    @end
    
    @implementation MainViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view from its nib.
    
        // 簡単のため、ナビゲーションバーにボタンを置く。
        UIBarButtonItem *action = [UIBarButtonItem.alloc initWithBarButtonSystemItem:UIBarButtonSystemItemAction
                                                                              target:self
                                                                              action:@selector(barAction:)];
        self.navigationItem.rightBarButtonItem = action;
    
        // imageView の subview に UIWebView をタイル状に敷き詰める
        self.webViews = [NSMutableArray array];
        CGFloat width = self.imageView.frame.size.width / 4;
        CGFloat currentY = 0.0f;
        while (currentY < self.view.frame.size.height) {
            for(int i=0; i<4; ++i){
                CGRect frame = CGRectMake(width * i, currentY, width, width);
                UIWebView *webView = [UIWebView.alloc initWithFrame:frame];
                [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.co.jp/"]]];
                [self.imageView addSubview:webView];    // 親(View) -> 子(UIImageView) -> 孫(UIWebView)
                [self.webViews addObject:webView];
            }
            currentY += width;
        }
    }
    
    - (void)barAction:(id)sender
    {
        // 親(View) -> 子(UIImageView) -> 孫(UIWebView) から親(View) -> 孫(UIWebView) へ
        UIWebView *webView = self.webViews[0];
        [webView removeFromSuperview];
        webView.frame = self.view.frame;
        [self.view addSubview:webView];
    }
    
[/code]


CC BY-SA 3.0
2015-02-10T12:54:15.670
6268
2015-02-10T12:54:15.670
5106
6255
answer


> 付け替えを行うとメモリから解放されてしまったりしているのでしょうか？

この「メモリから解放」という箇所についてだけ、2、3触れてみたいと思います。  
Objective-Cは、リファレンスカウンティング（Reference
Counting）という方法で、オブジェクト（インスタンス）の管理を行っています。それはARC（Automatic Reference
Counting）が有効でも同じです。ただ自動化されているかいないかだけ。ほかのインスタンスから参照されているあいだ、インスタンスは解放されず、保持されます。ほかのインスタンスから参照されなくなったら、あるいは参照しているインスタンスが解放されて、ひとつもなくなったら、そのインスタンスはいつでも解放される状態になります。  
NSArrayやNSDictionaryなどのコレクションクラスについて、コレクションクラスの要素になっているインスタンスは、要素であるあいだ解放されません。コレクションクラスが要素のインスタンスを参照していることになっているからです。要素から外される（removeObject:）と、コレクションクラス以外から参照されていなければ、そのインスタンスがいつでも解放される状態となります。  
UIViewにはsubviewsというNSArray型のプロパティがあり、Superviewは、Subviewをこのsubviewsで管理しています。なので、NSArrayと参照のしかたは同じです。addSubview:でSubviewにすると、Superviewが参照を行い、Superviewが保持されている限り、Subviewも保持されます。removeFromSuperviewで、Superviewから外されると、ほかから参照されていなければ、その元Subviewは、いつでも解放される状態になります。  
以上を踏まえれば、コードをたどりながら、メモリから解放されてしまうらしいインスタンスの参照関係を調べることで、メモリから解放されるのならば、解放されてもいい状態にになるタイミングを探ることができます。  
私がちょっと気になるのは、インスタンスを変数から変数に渡すときに、参照の受け渡しでなく、コピーになっている箇所がないか？という点です。コピー直後のインスタンスは、参照が0なので、スコープ（{〜}）から出て行けば、いつでも解放される状態となります。  
参照渡しか、コピー渡しかは、インスタンスのアドレスを調べればはっきりします。Objective-
Cのインスタンスは、ポインタで扱われることを思い出してください。

[code]

    NSLog(@"Subviews address = %p", targetView);
    
[/code]

このように記号%pで、インスタンス（ポインタ）のアドレスを出力できます。適宜コードの中にNSLog()を差し挟んで、Viewを追跡するのも、有効かもしれません。


CC BY-SA 3.0
2015-02-11T00:23:21.443
6285
2015-02-11T00:23:21.443
7362
6255
answer