iOS零碎记录

1.怎样打印一个结构体

CGRect rect = CGRectMake(0, 0, 320, 568);

    NSString *str = NSStringFromCGRect(rect); //结构体转化为字符串

    NSLog(@"%@",str);

2.保持后台长时间运行

-(void)logAction
{
    NSLog(@"保持后台");
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
    _timer =  [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(logAction) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
    UIApplication*   app = [UIApplication sharedApplication];
    __block    UIBackgroundTaskIdentifier bgTask;
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid){
                bgTask = UIBackgroundTaskInvalid;
            }
        });
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid){
                bgTask = UIBackgroundTaskInvalid;
            }
        });
    });
}

备注:beginBackgroundTaskWithExpirationHandler:是在告诉系统需要更多时间完成某件事,完成之后再通知它。
bgTask != UIBackgroundTaskInvalid是指系统响应留给我们时间

3.关于error:Cannot assign to ‘self’ outside of a method in the init family

 有时候我们重写父类的init方法时不注意将init后面的第一个字母写成了小写,在这个方法里面又调用父类的初始化方法(self = [super init];)时会报错,错误信息如下:error:Cannot assign to 'self' outside of a method in the init family
原因:只能在init方法中给self赋值,Xcode判断是否为init方法规则:方法返回id,并且名字以init+大写字母开头+其他  为准则。例如:- (id) initWithXXX;

4.自定义侧滑控制器和tabarController

ReSideMenu:https://github.com/romaonthego/RESideMenu

tabarController:https://github.com/ChenYilong/CYLTabBarController

5.smartsvn客户端(version客户端类似),一些.a文件无法识别,也就无法提交到svn!

解决办法如下:
在smartsvn客户端下面view->Ignored Files 勾选上就ok(version客户端类似操作)
svn使用地址:http://blog.sina.com.cn/s/blog_7b9d64af0102vb68.html

6.实例变量在block中的使用

@interface CharacteristicViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>{
@public
    BabyBluetooth *baby;
    NSMutableArray *sect;
  __block  NSMutableArray *readValueArray;

}

使用时:

[self->readValueArray addObject:[NSString stringWithFormat:@"%@",characteristics.value]];

或者

__weak typeof(self) weakSelf = self;
self.blkA = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;//加一下强引用,避免weakSelf被释放掉
NSLog(@"%@", strongSelf->_xxView); //不会导致循环引用.
};

在委托问题上出现循环引用问题已经是老生常谈了,本文也不再细讲,规避该问题的杀手锏也是简单到哭,一字诀:声明delegate时请用assign(MRC)或者weak(ARC),千万别手贱玩一下retain或者strong,毕竟这基本逃不掉循环引用了!

7.一个简化appDelegate的插件
https://github.com/xareelee/XAspect

8.判断UIViewController是否正在显示

if (self.isViewLoaded && self.view.window) {

    }

8.改变tableView的头部高度

 CGRect newFrame = _groupHeaderView.frame;
    if (newFrame.size.height ==195) return;
    newFrame.size.height =195;
    _groupHeaderView.frame = newFrame;
    [self.tableView setTableHeaderView:_groupHeaderView];

9.在线绘制流程图
https://www.processon.com

10.static 和 extern 的使用

static: 在一个A类.m外面定义一个static NSString * staticStr = @”static”;
要在另一个B类中使用到这个变量,则需要导入A类的头文件,然后可以直接使用staticStr。

extern:在一个A类.m外面定义一个NSString * externStr = @”extern”;
要在另一个B类中使用到这个变量,则需要导入A类的头文件,然后在使用的地方加个 extern NSString *externStr 后就 可以直接使用externStr。

11. 使用CocoaPods之后,头文件无法自动补齐问题

使用CocoaPods来管理三方库,还是比较方便的,但是突然发现一个美中不足的小问题,在使用import引入文件时,不能自动补齐,需要手工copy文件名,纠结了半天:
解决办法:
Target -> Build Settings ,User Header Search Paths条目中,添加 SRCROOT (PODS_ROOT),并且选择Recursive,递归搜索,然后就可以自动补齐了。

12.对OC中类的描述(转)
这里写图片描述
这里写图片描述

13.category和extension的使用

category的使用情况:
1.在不创建继承类的情况下实现对已有类的扩展。

2.简化类的开发工作(当一个类需要多个程序员协同开发的时候,Category可以将同一个类根据用途分别放在不同的源文件中,从而便于程序员独立开发相应的方法集合)。

3.将常用的相关的方法分组。

4.在没有源代码的情况下可以用来修复BUG。

5.统计埋点应用

category的特点:
1.不能通过property()添加成员变量,如果需要添加成员变量,则需要进行时重写set和get方法,否则使用时会闪退。

2.并没有什么界限分明的判定标准来作为何时用Category何时用添加子类的方法的指导。但是有以下几个指导性的建议:

如果需要添加一个新的变量,则需添加子类。
如果只是添加一个新的方法,用Category是比较好的选择。
在分类中增加的方法,会被子类所继承,而且在运行时跟其他方 法没有区别。
一般不要在分类中覆盖现有类中的方法。

extension的使用:
1.类的延展就如同时“匿名”的分类,延展中声明的方法在类本身的@implementation和它对应的@end之间实现。
2.类又是需要方法只有自己所见,我们可以通过延展的方式定义类的私有方法

两者区别:
Class Extension 和 Category 在语言机制上有着很大差别:Class Extension 在编译期就会将定义的 Ivar、属性、方法等直接合入主类,而 Category 在程序启动 Runtime Loading 时才会将属性(没 Ivar)和方法合入主类。

14.#ifdef DEBUG的使用
这里写图片描述

15.静态库和动态库

静态库:静态库在Objective-C里面以.a或者.framework作为后缀,目前开发者自己创建的库文件(Framework)其实都是以静态库的形式链接到执行文件的。链接时完整的拷贝到了可执行文件中,被多次使用就会有多份拷贝(eg:iOS8+的Extention中使用)。静态库文件一般都会比较大,因为所有要使用的数据都会被编译进去,而且如果库文件的某个函数改变了,那么就又需要重新编译新的库文件了,优点就是编译后的执行程序不需要外部的函数库支持,因为所有的函数都已经被编译进去了。(注:静态库多的话会引起包增大)
动态库:动态库在Objective-C里面以dylib或者.framework最为后缀,系统为我们提供的framework就是动态库,目前开发者是不允许使用动态库的,因为我们自己创建的库文件虽然buildSetting中的Mach-O Type设置为Dynamic Library,但是使用时直接链接到程序里面的,而不是放在服务器上进行更新,开发者如果使用动态库放在服务器上,然后动态的加载dlopen是不会通过审核的,不然Apple的审核就没有意义了。动态库在链接时不复制,程序运行时由系统动态加载到内存,系统只加载一次,多个程序间共用,节省内存,而且升级方便。

16.状态栏颜色设置
有两种方法:

一、在info.plist中,将View controller-based status bar appearance设为NO//白色
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;

二、在info.plist中,将View controller-based status bar appearance设为YES,或者没有设置。
View controller-based status bar appearance的默认值就是YES。
如果View controller-based status bar appearance为YES。
则[UIApplication sharedApplication].statusBarStyle 无效。
用下面的方法:
1、在vc中重写vc的preferredStatusBarStyle方法。
-(UIStatusBarStyle)preferredStatusBarStyle{return UIStatusBarStyleDefault;
}

2、在viewDidload中调用:[self setNeedsStatusBarAppearanceUpdate];

但是,当vc在nav中时,上面方法没用,vc中的preferredStatusBarStyle方法根本不用被调用。
原因是,[self setNeedsStatusBarAppearanceUpdate]发出后,
只会调用navigation controller中的preferredStatusBarStyle方法,
vc中的preferredStatusBarStyley方法跟本不会被调用。

解决办法有两个:

方法一:

设置navbar的barStyle 属性会影响status bar 的字体和背景色。如下。
//status bar的字体为白色
//导航栏的背景色是黑色。
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
//status bar的字体为黑色
//导航栏的背景色是白色,状态栏的背景色也是白色。
//self.navigationController.navigationBar.barStyle = UIBarStyleDefault;

方法二:

自定义一个nav bar的子类,在这个子类中重写preferredStatusBarStyle方法:
MyNav* nav = [[MyNav alloc] initWithRootViewController:vc];
self.window.rootViewController = nav;

@implementation MyNav

- (UIStatusBarStyle)preferredStatusBarStyle
{
UIViewController* topVC = self.topViewController;
return [topVC preferredStatusBarStyle];

}

17.电池信息获取

//电池的状态是可监听的  
[UIDevice currentDevice].batteryMonitoringEnabled = YES;  
//huoqu电池的状态  
switch ([UIDevice currentDevice].batteryState) {  
    case UIDeviceBatteryStateUnknown:  
        NSLog(@"电池的状态未知");  
        break;  
    case UIDeviceBatteryStateCharging:  
        NSLog(@"电池正在充电");  
        break;  
    case UIDeviceBatteryStateUnplugged:  
        NSLog(@"电池未充电");  
        break;  
    case UIDeviceBatteryStateFull:  
        NSLog(@"电池电量充满");  
        break;  
    default:  
        break;  
}  

//获取当前电池的电量  
NSLog(@"当前电池的电量百分比是%3.0f%%",([[UIDevice currentDevice] batteryLevel]) *100);

18.绘制圆角tableView

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(tintColor)]) {
        if (tableView == self.tableView) {
            // 圆角弧度半径
            CGFloat cornerRadius = 5.f;
            // 设置cell的背景色为透明,如果不设置这个的话,则原来的背景色不会被覆盖
            cell.backgroundColor = UIColor.clearColor;

            // 创建一个shapeLayer
            CAShapeLayer *layer = [[CAShapeLayer alloc] init];
            // 创建一个可变的图像Path句柄,该路径用于保存绘图信息
            CGMutablePathRef pathRef = CGPathCreateMutable();
            // 获取cell的size
            CGRect bounds = CGRectInset(cell.bounds, 0, 0);

            // CGRectGetMinY:返回对象顶点坐标
            // CGRectGetMaxY:返回对象底点坐标
            // CGRectGetMinX:返回对象左边缘坐标
            // CGRectGetMaxX:返回对象右边缘坐标

            // 这里要判断分组列表中的第一行,每组section的第一行,每组section的中间行
            BOOL addLine = NO;
            // CGPathAddRoundedRect(pathRef, nil, bounds, cornerRadius, cornerRadius);
            if (indexPath.row == 0) {
                // 初始起点为cell的左下角坐标
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
                // 起始坐标为左下角,设为p1,(CGRectGetMinX(bounds), CGRectGetMinY(bounds))为左上角的点,设为p1(x1,y1),(CGRectGetMidX(bounds), CGRectGetMinY(bounds))为顶部中点的点,设为p2(x2,y2)。然后连接p1和p2为一条直线l1,连接初始点p到p1成一条直线l,则在两条直线相交处绘制弧度为r的圆角。
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds), CGRectGetMidX(bounds), CGRectGetMinY(bounds), cornerRadius);
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
                // 终点坐标为右下角坐标点,把绘图信息都放到路径中去,根据这些路径就构成了一块区域了
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds));
                addLine = YES;
            } else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
                // 初始起点为cell的左上角坐标
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds), CGRectGetMidX(bounds), CGRectGetMaxY(bounds), cornerRadius);
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
                // 添加一条直线,终点坐标为右下角坐标点并放到路径中去
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
            } else {
                // 添加cell的rectangle信息到path中(不包括圆角)
                CGPathAddRect(pathRef, nil, bounds);
                addLine = YES;
            }
            // 把已经绘制好的可变图像路径赋值给图层,然后图层根据这图像path进行图像渲染render
            layer.path = pathRef;
            // 注意:但凡通过Quartz2D中带有creat/copy/retain方法创建出来的值都必须要释放
            CFRelease(pathRef);
            // 按照shape layer的path填充颜色,类似于渲染render
           // layer.fillColor = [UIColor colorWithWhite:1.f alpha:0.8f].CGColor;
            layer.fillColor = [UIColor whiteColor].CGColor;
            // 添加分隔线图层
            if (addLine == YES) {
                CALayer *lineLayer = [[CALayer alloc] init];
                CGFloat lineHeight = (1.f / [UIScreen mainScreen].scale);
                lineLayer.frame = CGRectMake(CGRectGetMinX(bounds), bounds.size.height-lineHeight, bounds.size.width, lineHeight);
                // 分隔线颜色取自于原来tableview的分隔线颜色
                lineLayer.backgroundColor = tableView.separatorColor.CGColor;
                [layer addSublayer:lineLayer];
            }

            // view大小与cell一致
            UIView *roundView = [[UIView alloc] initWithFrame:bounds];
            // 添加自定义圆角后的图层到roundView中
            [roundView.layer insertSublayer:layer atIndex:0];
            roundView.backgroundColor = UIColor.clearColor;
            //cell的背景view
            //cell.selectedBackgroundView = roundView;
            cell.backgroundView = roundView;

        }
    }
}

19.常量定义方式

在项目中经常需要定义一些常量和一些类型,通常我们是在需要的那个类上直接定义,这样虽然快速,但是项目大的话就使得代码比较散乱,所以我们最好是定义在一个统一的头文件中,如下:

#ifndef INTU_LOCATION_REQUEST_DEFINES_H
#define INTU_LOCATION_REQUEST_DEFINES_H

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

#if __has_feature(nullability)
#   define __INTU_ASSUME_NONNULL_BEGIN      NS_ASSUME_NONNULL_BEGIN
#   define __INTU_ASSUME_NONNULL_END        NS_ASSUME_NONNULL_END
#   define __INTU_NULLABLE                  nullable
#else
#   define __INTU_ASSUME_NONNULL_BEGIN
#   define __INTU_ASSUME_NONNULL_END
#   define __INTU_NULLABLE
#endif

#if __has_feature(objc_generics)
#   define __INTU_GENERICS(type, ...)       type<__VA_ARGS__>
#else
#   define __INTU_GENERICS(type, ...)       type
#endif

#ifdef NS_DESIGNATED_INITIALIZER
#   define __INTU_DESIGNATED_INITIALIZER    NS_DESIGNATED_INITIALIZER
#else
#   define __INTU_DESIGNATED_INITIALIZER
#endif

static const CLLocationAccuracy kINTUHorizontalAccuracyThresholdCity =         5000.0;  // in meters
static const CLLocationAccuracy kINTUHorizontalAccuracyThresholdNeighborhood = 1000.0;  // in meters
static const CLLocationAccuracy kINTUHorizontalAccuracyThresholdBlock =         100.0;  // in meters
static const CLLocationAccuracy kINTUHorizontalAccuracyThresholdHouse =          15.0;  // in meters
static const CLLocationAccuracy kINTUHorizontalAccuracyThresholdRoom =            5.0;  // in meters

static const NSTimeInterval kINTUUpdateTimeStaleThresholdCity =             600.0;  // in seconds
static const NSTimeInterval kINTUUpdateTimeStaleThresholdNeighborhood =     300.0;  // in seconds
static const NSTimeInterval kINTUUpdateTimeStaleThresholdBlock =             60.0;  // in seconds
static const NSTimeInterval kINTUUpdateTimeStaleThresholdHouse =             15.0;  // in seconds
static const NSTimeInterval kINTUUpdateTimeStaleThresholdRoom =               5.0;  // in seconds

/** The possible states that location services can be in. */
typedef NS_ENUM(NSInteger, INTULocationServicesState) {
    /** User has already granted this app permissions to access location services, and they are enabled and ready for use by this app.
        Note: this state will be returned for both the "When In Use" and "Always" permission levels. */
    INTULocationServicesStateAvailable,
    /** User has not yet responded to the dialog that grants this app permission to access location services. */
    INTULocationServicesStateNotDetermined,
    /** User has explicitly denied this app permission to access location services. (The user can enable permissions again for this app from the system Settings app.) */
    INTULocationServicesStateDenied,
    /** User does not have ability to enable location services (e.g. parental controls, corporate policy, etc). */
    INTULocationServicesStateRestricted,
    /** User has turned off location services device-wide (for all apps) from the system Settings app. */
    INTULocationServicesStateDisabled
};

/** The possible states that heading services can be in. */
typedef NS_ENUM(NSInteger, INTUHeadingServicesState) {
    /** Heading services are available on the device */
    INTUHeadingServicesStateAvailable,
    /** Heading services are available on the device */
    INTUHeadingServicesStateUnavailable,
};

/** A unique ID that corresponds to one location request. */
typedef NSInteger INTULocationRequestID;

/** A unique ID that corresponds to one heading request. */
typedef NSInteger INTUHeadingRequestID;

/** An abstraction of both the horizontal accuracy and recency of location data.
    Room is the highest level of accuracy/recency; City is the lowest level. */
typedef NS_ENUM(NSInteger, INTULocationAccuracy) {
    // 'None' is not valid as a desired accuracy.
    /** Inaccurate (>5000 meters, and/or received >10 minutes ago). */
    INTULocationAccuracyNone = 0,

    // The below options are valid desired accuracies.
    /** 5000 meters or better, and received within the last 10 minutes. Lowest accuracy. */
    INTULocationAccuracyCity,
    /** 1000 meters or better, and received within the last 5 minutes. */
    INTULocationAccuracyNeighborhood,
    /** 100 meters or better, and received within the last 1 minute. */
    INTULocationAccuracyBlock,
    /** 15 meters or better, and received within the last 15 seconds. */
    INTULocationAccuracyHouse,
    /** 5 meters or better, and received within the last 5 seconds. Highest accuracy. */
    INTULocationAccuracyRoom,
};

/** An alias of the heading filter accuracy in degrees.
    Specifies the minimum amount of change in degrees needed for a heading service update. Observers will not be notified of updates less than the stated filter value. */
typedef CLLocationDegrees INTUHeadingFilterAccuracy;

/** A status that will be passed in to the completion block of a location request. */
typedef NS_ENUM(NSInteger, INTULocationStatus) {
    // These statuses will accompany a valid location.
    /** Got a location and desired accuracy level was achieved successfully. */
    INTULocationStatusSuccess = 0,
    /** Got a location, but the desired accuracy level was not reached before timeout. (Not applicable to subscriptions.) */
    INTULocationStatusTimedOut,

    // These statuses indicate some sort of error, and will accompany a nil location.
    /** User has not yet responded to the dialog that grants this app permission to access location services. */
    INTULocationStatusServicesNotDetermined,
    /** User has explicitly denied this app permission to access location services. */
    INTULocationStatusServicesDenied,
    /** User does not have ability to enable location services (e.g. parental controls, corporate policy, etc). */
    INTULocationStatusServicesRestricted,
    /** User has turned off location services device-wide (for all apps) from the system Settings app. */
    INTULocationStatusServicesDisabled,
    /** An error occurred while using the system location services. */
    INTULocationStatusError
};

/** A status that will be passed in to the completion block of a heading request. */
typedef NS_ENUM(NSInteger, INTUHeadingStatus) {
    // These statuses will accompany a valid heading.
    /** Got a heading successfully. */
    INTUHeadingStatusSuccess = 0,

    // These statuses indicate some sort of error, and will accompany a nil heading.
    /** Heading was invalid. */
    INTUHeadingStatusInvalid,

    /** Heading services are not available on the device */
    INTUHeadingStatusUnavailable
};

/**
 A block type for a location request, which is executed when the request succeeds, fails, or times out.

 @param currentLocation The most recent & accurate current location available when the block executes, or nil if no valid location is available.
 @param achievedAccuracy The accuracy level that was actually achieved (may be better than, equal to, or worse than the desired accuracy).
 @param status The status of the location request - whether it succeeded, timed out, or failed due to some sort of error. This can be used to
               understand what the outcome of the request was, decide if/how to use the associated currentLocation, and determine whether other
               actions are required (such as displaying an error message to the user, retrying with another request, quietly proceeding, etc).
 */
typedef void(^INTULocationRequestBlock)(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status);

/**
 A block type for a heading request, which is executed when the request succeeds.

 @param currentHeading  The most recent current heading available when the block executes.
 @param status          The status of the request - whether it succeeded or failed due to some sort of error. This can be used to understand if any further action is needed.
 */
typedef void(^INTUHeadingRequestBlock)(CLHeading *currentHeading, INTUHeadingStatus status);

#endif /* INTU_LOCATION_REQUEST_DEFINES_H */

20.线程安全之@synchronized的用法

转自http://www.cnblogs.com/jukaiit/p/5570056.html

@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用。

这里写图片描述

例如:一个电影院,有3个售票员。一场电影的总数量固定。3个售票员售票时,要判断是非还有余票。

#import "ViewController.h"

@interface ViewController ()
/** 售票员01 */
@property (nonatomic, strong) NSThread *thread01;
/** 售票员02 */
@property (nonatomic, strong) NSThread *thread02;
/** 售票员03 */
@property (nonatomic, strong) NSThread *thread03;

/** 票的总数 */
@property (nonatomic, assign) NSInteger ticketCount;

/** 锁对象 */
//@property (nonatomic, strong) NSObject *locker;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

//    self.locker = [[NSObject alloc] init];

    self.ticketCount = 100;

    self.thread01 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread01.name = @"售票员01";

    self.thread02 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread02.name = @"售票员02";

    self.thread03 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread03.name = @"售票员03";
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.thread01 start];
    [self.thread02 start];
    [self.thread03 start];
}

- (void)saleTicket
{
    while (1) {
        @synchronized(self) {
            // 先取出总数
            NSInteger count = self.ticketCount;
            if (count > 0) {
                self.ticketCount = count - 1;
                NSLog(@"%@卖了一张票,还剩下%zd张", [NSThread currentThread].name, self.ticketCount);
            } else {
                NSLog(@"票已经卖完了");
                break;
            }
        }
    }
}

@end

21.获取顶层控制器

- (UIViewController *)topViewController {
    UIViewController *resultVC;
    resultVC = [self _topViewController:[[UIApplication sharedApplication].keyWindow rootViewController]];
    while (resultVC.presentedViewController) {
        resultVC = [self _topViewController:resultVC.presentedViewController];
    }
    return resultVC;
}

- (UIViewController *)_topViewController:(UIViewController *)vc {
    if ([vc isKindOfClass:[UINavigationController class]]) {
        return [self _topViewController:[(UINavigationController *)vc topViewController]];
    } else if ([vc isKindOfClass:[UITabBarController class]]) {
        return [self _topViewController:[(UITabBarController *)vc selectedViewController]];
    } else {
        return vc;
    }
    return nil;
}
//使用方法

UIViewController *topmostVC = [self topViewController];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值