コンテンツへスキップ

iOS7で、カスタムしたUIPageControleが落ちる件

iOS7にした途端、カスタムしたUIPageControlを使ったページが落ちるようになった。

以下の実装方法を使っていたんだけど、なんだこれ〜っと調べてみると以下の様なことがわかった。
http://ria.surfboard.co.jp/blog/2010/12/08/uipagecontrolcustomise/

問題は「- (void)updateDots」部分。
まず、iOS6までのUIPageControlは、自身のSubViewsにUIImageViewを抱えている。
しかし、iOS7ではUIImageViewではなく、UIViewを抱えている。

当然、UIViewにsetImageなんてできないから落ちる、というわけです。

これってキャストすればよもや動かないか?と思ったけどダメ。

対応策としては、そのUIViewに新たにUIImageViewをセットすることで解決した。

コードは以下の様な感じ

- (void) updateDots
{
    if(_imageCurrent || _imageNormal)
    {
        // Get subviews
        NSArray* dotViews = self.subviews;
        LOG(@"%@",dotViews);
        // iOS6までは、今までこのSubViewsにUIImageViewが入ってきていたが
        // iOS7ではUIViewに変更されている。故に落ちてしまう。
        for(int i = 0; i < dotViews.count; ++i)
        {
            NSObject *obj = [dotViews objectAtIndex:i];
            
            // なので、内容クラスで分岐する
            if ([obj isKindOfClass:[UIImageView class]]) {
                UIImageView* dot = (UIImageView *)obj;
                // Set image
                if (i == self.currentPage) {
                    dot.image =_imageCurrent;
                }
                else{
                    dot.image =_imageNormal;
                }
            }
            else{
                // iOS7では以下の対応になる
                UIView *view = (UIView *)obj;
                
                if (view.subviews.count) {
                    [view.subviews[0] removeFromSuperview];
                }
                
                UIImageView *dot = [UIImageView new];
                dot.frame = view.bounds;
                
                // Set image
                if (i == self.currentPage) {
                    dot.image =_imageCurrent;
                }
                else{
                    dot.image =_imageNormal;
                }
                
                [view addSubview:dot];
                
            }
        }
    }
}

もしくはiOS7でUIPageControl使う時は素直に「- (void)setCurrentPageIndicatorTintColor:」することにする。

#defineを使ったAPIURL管理

URLを#defineを使って一元管理する。
至って簡単で以下のようにする

#define API_URL_DOMAIN          @"http://api.xxxxx.xxxxxx"
#define AUTH_API_URL            [NSString stringWithFormat:@"%@/API/auth/", API_URL_DOMAIN];

こんな風にすれば、ifdefでルートの向きを変えたりとっても簡単にできる。
一つのhファイルにすべて格納することもできるし、楽に管理ができるようになる。

当然っちゃ当然だけど、いろいろと活用できるのなあ、#defineって。

便利な#define一覧コピペ用メモ

#define ApplicationDelegate                 ((AppDelegate *)[[UIApplication sharedApplication] delegate])
#define UserDefaults                        [NSUserDefaults standardUserDefaults]
#define SharedApplication                   [UIApplication sharedApplication]
#define Bundle                              [NSBundle mainBundle]
#define MainScreen                          [UIScreen mainScreen]
#define ShowNetworkActivityIndicator()      [UIApplication sharedApplication].networkActivityIndicatorVisible = YES
#define HideNetworkActivityIndicator()      [UIApplication sharedApplication].networkActivityIndicatorVisible = NO
#define NetworkActivityIndicatorVisible(x)  [UIApplication sharedApplication].networkActivityIndicatorVisible = x
#define NavBar                              self.navigationController.navigationBar
#define TabBar                              self.tabBarController.tabBar
#define NavBarHeight                        self.navigationController.navigationBar.bounds.size.height
#define TabBarHeight                        self.tabBarController.tabBar.bounds.size.height
#define ScreenRect                          [[UIScreen mainScreen] bounds]
#define ScreenWidth                         [[UIScreen mainScreen] bounds].size.width
#define ScreenHeight                        [[UIScreen mainScreen] bounds].size.height
#define TouchHeightDefault                  44
#define TouchHeightSmall                    32
#define ViewWidth(v)                        v.frame.size.width
#define ViewHeight(v)                       v.frame.size.height
#define ViewX(v)                            v.frame.origin.x
#define ViewY(v)                            v.frame.origin.y
#define SelfViewHeight                      self.view.bounds.size.height
#define RectX(f)                            f.origin.x
#define RectY(f)                            f.origin.y
#define RectWidth(f)                        f.size.width
#define RectHeight(f)                       f.size.height
#define RectSetWidth(f, w)                  CGRectMake(RectX(f), RectY(f), w, RectHeight(f))
#define RectSetHeight(f, h)                 CGRectMake(RectX(f), RectY(f), RectWidth(f), h)
#define RectSetX(f, x)                      CGRectMake(x, RectY(f), RectWidth(f), RectHeight(f))
#define RectSetY(f, y)                      CGRectMake(RectX(f), y, RectWidth(f), RectHeight(f))
#define RectSetSize(f, w, h)                CGRectMake(RectX(f), RectY(f), w, h)
#define RectSetOrigin(f, x, y)              CGRectMake(x, y, RectWidth(f), RectHeight(f))
#define Rect(x, y, w, h)                    CGRectMake(x, y, w, h)
#define DATE_COMPONENTS                     NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
#define TIME_COMPONENTS                     NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit
#define FlushPool(p)                        [p drain]; p = [[NSAutoreleasePool alloc] init]
#define RGB(r, g, b)                        [UIColor colorWithRed:(r)/255.f green:(g)/255.f blue:(b)/255.f alpha:1.f]
#define RGBA(r, g, b, a)                    [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]

#define StatusBarHeight                     [UIApplication sharedApplication].statusBarFrame.size.height
#define DefaultToolbarHeight                self.navigationController.navigationBar.frame.size.height

#define sumX(view)                          view.frame.size.width + view.frame.origin.x
#define sumY(view)                          view.frame.size.height + view.frame.origin.y

UIWebViewで、証明書切れのHTTPSに繋ぐ方法

テスト環境とかでこのへん詰まったのでメモ。

NSURLRequestを拡張して無理やり通す。

@interface NSURLRequest(SSL)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host;
@end

@implementation NSURLRequest(SSL)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host {
    return YES;
}
@end

でもこれはあくまでテストのために使うべきで、このまま行くとリジェクト食らう可能性が高いのでリリース時には気をつけること。

NSTimerがUITableViewをスクロールすると止まるのを解決する

コードは以下

    timer = [NSTimer timerWithTimeInterval:1.0
                                    target:self
                                  selector:@selector(timerAction)
                                  userInfo:nil
                                   repeats:YES];
    
    [timer fire];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

ふつうにTimetはinvaliedしたりFireしたりしてやれば大丈夫。

UITabBarControllerのTabBarを非表示にする

タブバーを非表示にすると、下にスペースが出来ちゃってやな感じになる。
そのスペースを無くして表示するには?

以下のように、TabBarControllerのサブクラスに実装する


BOOL hiddenTabBar;

- (void) hideTabBar {
    
    for(UIView *view in self.view.subviews)
    {
        CGRect _rect = view.frame;
        if([view isKindOfClass:[UITabBar class]])
        {
            if (hiddenTabBar) {
                _rect.origin.y = ScreenHeight - self.tabBar.frame.size.height;
                [view setFrame:_rect];
            } else {
                _rect.origin.y = ScreenHeight;
                [view setFrame:_rect];
            }
        } else {
            if (hiddenTabBar) {
                _rect.size.height = ScreenHeight - self.tabBar.frame.size.height;
                [view setFrame:_rect];
            } else {
                _rect.size.height = ScreenHeight;
                [view setFrame:_rect];
            }
        }
    }
    hiddenTabBar = !hiddenTabBar;
}

これでスペースをとられることなく非表示に出来る。

スペースを消すと、並行移動とラッピングビューが残るので、この2つの機能だけ使いたいときは便利。
tabbarControllerを呼び出すときはappDelegateから呼び出すようにしないと動かないので注意が必要。

参考:http://www.developers-life.com/hide-uitabbarcontrolleruitabbar-with-animation.html

UINavigationControllerのViewに貼ったViewに、今表示しているViewControllerからアクセスする

前回の「どのViewControllerに貼られているか?」の続きみたいなもんです。
これをするために前回のをやりました。

シチュエーション

画面遷移してもずっと存在し続けるメニューを作りたいなー。
でもタブとかじゃなくってViewの上に乗っかってて、邪魔なときは非表示にしたりアニメーションを自由にしたい。

コード

※ShareViewというのは、NavigationControllerのViewに貼り付けるために作ったクラスです。別になんでも構わないと思うけど、UIViewだと判別しにくくなると思います。

Viewの貼り付け

- (void)addShareView{
    
    // ShareViewが作られていないときに限って作成しAddする
    if ([self findShareView] == nil) {
        
        CGRect navRect = self.navigationController.view.frame;
        
        float height = SHAREVIEW_HEIGHT;
        
        ShareView *shareView = [[ShareView alloc] initWithFrame:CGRectMake(0, navRect.size.height - height, 320, height)];
        
        [self.navigationController.view addSubview:shareView];
    }
}

Viewの取得

- (ShareView *)findShareView{
    
    NSArray *views = self.navigationController.view.subviews;
    
    ShareView *sView = nil;
    
    for (UIView *view in views) {
        if ([view isKindOfClass:[ShareView class]]) {
            sView = (ShareView *)view;
            return sView;
        }
    }
    // なかったらnilを返す
    return nil;

}

Viewの表示

- (void)showShareView{
    
    ShareView *sView = [self findShareView];
    [sView hide:NO animated:YES];// ここはお好きな表示方法を
    
}

Viewの非表示

- (void)hideShareView{
    
    ShareView *sView = [self findShareView];
    [sView hide:YES animated:YES];// ここはお好きな非表示方法を

}

こんなかんじ。

これらを実装したViewControllerを作成して、操作したいControllerで継承しちゃえば、継承したコントローラーでなら表示非表示を管理出来ます。
Viewに貼りつけたボタンなどから現在のViewControllerを取得するには、以前書いた記事のようにすれば取得できるので、これで交信できるようになります。