更新中......(部分省略)
10.19已更新
10.20已更新
11.4 已更新
- 文章推荐:
Xcode9新特性
1.启动多个模拟器
方案一
- 从
Xcode
选择不同的模拟器,启动新的模拟器。方案二
- 从模拟器
menu
上的Hardware
---Device
,选择新的模拟器启动。
2.WiFi无线安装App
- 操作的步骤如下(注意:必须是
iOS11
,iPhone
和Mac
处于同一WiFi
下。):- 接线连接
iPhone
。点选Xcode
menu
的Window
,选择Devices and Simulators
。 - 勾选
Connect via network
,连线到iPhone
。如果连线顺利,iPhone
旁会出现如下选项。 - 如果刚刚没有出现网路图示,或是拔线后,
iPhone
不理我们,在Devices and Simulators
视窗显示Disconnected
。此时Xcode
找不到iPhone
,也就无法顺利安装App
。 - 在
Devices and Simulators
视窗上选择iPhone
后,从右键选单点选Connect via IP Address
,输入iPhone
的IP
后,点选Connect
连线。 - IP 地址,则可从
iPhone
设定App
的WiFi
页面查询。
- 接线连接
3.错误提示
- 错误可以多行显示,
Fix
会自动出现,点选即可修正问题。
4.按住 command
加+
可将代码放大,command
加-
可将代码縮小。
5.提示选单
- 將鼠标移到
{ }
、( )
或是class
、func
、if
、for
等关键字,按住command
建,Xcode
將表示对应的class
、function
、if
、for
代码块。- 鼠标移到方法上,按
command
建,会出现提示选单。 - 按住
command
建再点击Jump To Definition
,跳到方法的定义。 - 如果想利用快速建跳到定义,按住
command + control
再点击。 - 回到以前的样子:
- 鼠标移到方法上,按
- 介绍:
-
Jump to Definition
跳转到定义的方法 -
Fold
折叠方法 -
Rename
重命名
-
6.swift
重新命名、自动补全协议的required方法,Extract Method
自动提取方法
swift
重新命名Extract Method
自动提取方法
7.深度整合 github
- 将
Xcode
的代码上传到github
-
以前:先在
github
上建立远程仓库,然后再在Xcode
中设置远程仓库,最后执行push
上传。 -
现在:先本地
git
初始化代码,进行git
管理。 - 再在打开项目的工具条选择第二个图标,选择
Create Remote...
- 填写信息
-
以前:先在
8.给顏色添加名字
-
Assets.xcassets
现在除了加入图片,还可以加入有名字的颜色,方便我们之后在Storyboard
或程式里使用。 - 可以在
Storyboard
控件选择颜色时,在Named Colors
下看到我們取的顏色名字。 -
[UIColor colorNamed:@"Color"]
iOS11新方法
9.新的编译系统
- 新的编译器已经用
Swift
重写了,性能得到了很大的提升。
10.Finder
和 Simulator
共享文件
-
Simulator
具有Finder
扩展,我们可以直接从Finder
窗口共享文件给Simulator
.
11.折叠代码
- 菜单的
Fold
,用来折叠方法 -
command+option+左键
,快速折叠方法
12.Folder和Group的同步问题
- 在
Xcode9
中重名命Folder
,Finder
中的也同步的改变了,我们之前建议一个虚拟的group
,并不会在对应的文件夹中建立真实的目录.Xcode9
中,默认行为改变了, 变成了会建立对应的真实文件夹, 如果你需要像之前那样只是建立虚拟的group
, 选择New Group without Folder
即可! - 苹果给出了标识来区分的, 虚拟的左下角有个小的三角形.
iOS11适配
1.定位相关
- 如果原来申请的权限是始终允许
NSLocationAlwaysUsageDescription
,那么需要在保留原来的key
的基础上增加NSLocationWhenInUseUsageDescription
和NSLocationAlwaysAndWhenInUsageDescription
。
2.系统相册相关(待验证)
- iOS11之前相册对应的
key
是NSPhotoLibraryUsageDescription
,iOS11对应的Key
是NSPhotoLibraryAddUsageDescription
。同定位的Key
一样,由于key
没有兼容性,所以需要保留原key
以兼容iOS10
及之前版本。
3.关于UIScrollView
初始位置变化的问题
- iOS11废弃了
UIViewController
的automaticallyAdjustsScrollViewInsets
属性,位置需要手动调整。 - iOS11中为
UIScrollView
新增了contentInsetAdjustmentBehavior
属性
// Swift
if #available(iOS 11.0, *) {
UIScrollView.appearance().contentInsetAdjustmentBehavior = .never
}
// OC
if (@available(iOS 11.0, *)) {
[UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
[UITableView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
[UICollectionView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
[UIWebView appearance].scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
//底下这三句是解决mjrefresh 上拉偏移的bug
[UITableView appearance].estimatedRowHeight = 0;
[UITableView appearance].estimatedSectionHeaderHeight = 0;
[UITableView appearance].estimatedSectionFooterHeight = 0;
} else {
// Fallback on earlier versions
}
// 或者
#ifdef __IPHONE_11_0
#endif
if (UIScreen.mainScreen.bounds.size.height == 812) {
NSLog(@"this is iPhone X");
}
}
4.UIVisualEffectView相关的崩溃
-
iOS11
之前可以将UIView
直接加到(addSubview
)UIVisualEffectView
上面, -
iOS11
上面这么做会导致crash
。- 正确的姿势是:将
UIView
addSubview
到UIVisualEffectView
的contentView
上。
- 正确的姿势是:将
5.关于上传商店相关改变
- 之前没有
1024*1024
的icon
,同样可以提交商店审核,但是现在不行了。你会在用Application Loader
上传完成后收到一个warning
,但是在提交审核(包括beta
测试版本)时被告知不允许提交。 - 而且注意,这个
1024
的图片一定要去掉alpha
通道。可以在github
上搜索Alpha-Channel-Remover
,用这个工具去掉alpha
通道。 - 在
Assets.xcassets
添加。
6.针对 iPhoneX启动图 适配
- 如果之前的
APP
在iPhoneX
屏幕没填充满,上下有黑色区域,应该是你的app
之前未用LaunchScreen.Storyboard
作为启动页面,可以使用LaunchScreen
来当做入场页面,这样APP才会自动适配为iPhoneX
的大小。或者修改Assets
中的LaunchImage
,添加iPhoneX
的尺寸图如下(1125*2436
)。
7.iOS11
安全区域 适配
- 安全区域定义了
view
中可视区域的部分,帮助我们将view放置在整个屏幕的可视的部分。 -
iPhone X
取消了Home
键,实现了高屏占比。所以默认View
的区域是全屏幕屏幕,四周有圆角、顶部有“刘海”、底部有手势区域 - 导航栏高度是
44 + 44
- 安全区域: 顶部从
44
到距离底部34 为安全区域 -
Safe Area
要求最低支持iOS9.0
(待考证)
iOS11的UIViewController和UIView新加了-(void)viewSafeAreaInsetsDidChange方法,当安全区域改变后该方法会被调用。然后在该方法中根据safeAreaInses属性更新子视图中控件的布局位置。
当然如果你要改变一个UIViewController的safeAreaInsets值, 可以通过设置addtionalSafeAreaInsets属性来实现, 例如你要自定义一些特殊的样式时。
需要注意的是 viewSafeAreaInsetsDidChange 在UIViewController 中第一次调用的时间是在 -(void)viewWillAppear:(BOOL)animated 调用之后, 在 - (void)viewWillLayoutSubviews 调用之前。所以可以在 viewWillAppear 里设置受影响的页面的 addtionalSafeAreaInsets 属性。
- (void)viewSafeAreaInsetsDidChange{
[super viewSafeAreaInsetsDidChange];
if (@available(iOS 11.0, *)) {
NSLog(@"safeAreaInset list= %@",NSStringFromUIEdgeInsets(self.view.safeAreaInsets));
NSLog(@"safeAreaLayout list= %@",self.view.safeAreaLayoutGuide);
}
}
8.导航栏高度的变化
iOS11
之前导航栏默认高度为64pt
(这里高度指statusBar
+NavigationBar
)iOS11
之后如果设置了prefersLargeTitles = YES
则为96pt
,默认情况下还是64pt
,但在iPhoneX
上由于刘海的出现statusBar
由以前的20pt
变成了44pt
,所以iPhoneX
上高度变为88pt
,如果项目里隐藏了导航栏加了自定义按钮之类的,这里需要注意适配一下。在
iOS11
导航栏多了一个LargeTitleView
,专门显示大字标题用的,整个导航栏的高度达到了96p
,这不包括状态栏的高度,也就是说,整个app
顶部高度达到了116p,其中statusbar=20
,title=44
,largetitle=52
,不过默认是64p
;当然,iPhoneX
的高度会更高点,如果不显示大字标题,顶部的高度也达到了88
,statusbar=44
,title=44
,如果显示大字标题,则高度变成了140
,statusbar=44
,title=44
,largetitle=52
,也就是说,iPhoneX
的刘海高度为44p
,大字标题如下图
9. UITableView
-
ios11
里默认启用Self-Sizing
,tableView
不会一次性计算所有的cell
的高度了,只会计算当前屏幕能够显示的cell
个数再加上几个,滑动时,tableView
不停地得到新的cell
,更新自己的contenSize
,在滑到最后的时候,会得到正确的contenSize
,所有estimated
高度默认值从iOS11
之前的 0 改变为UITableViewAutomaticDimension
,如果不想开启的话可以用下面的方法关闭.
tableView.estimatedRowHeight = 0;
tableView.estimatedSectionHeaderHeight = 0;
tableView.estimatedSectionFooterHeight = 0;
官方视频总结
1.iOS9 and later
2.
3.
4.
5.新方法介绍
UIBarButtonItem的方法
largeContentSizeImage 用于视觉障碍的用户显示的图像。
landscapeImagePhone 用于以横向方向表示项目的图像。
navigationBar.prefersLargeTitles 标题是否应以大格式显示。
navigationItem.largeTitleDisplayMode 显示导航栏的标题时使用的模式。
navigationItem.searchController 搜索控制器集成到您的导航界面
navigationItem.hidesSearchBarWhenScrolling 在滚动任何底层内容时是否隐藏综合搜索栏。
UIView的方法
layoutMarginsGuide 表示视图边缘的布局指南。(iOS9的方法)
directionalLayoutMargins 在视图中布局内容时使用的默认间距,同时考虑到当前的语言方向。
控制器的方法
viewRespectsSystemMinimumLayoutMargins 如果你设置该属性为"false",你就可以改变你的layout margins为任意你想设置的值,包括0
...
自己适配问题
1.导航条
-
[[UIBarButtonItem alloc] initWithCustomView:button];
,这里button
是使用XIB
加载。 - 使用以上方法时,注意
button
要使用autolayout
布局,保证父视图的宽高。否则无响应事件 - 还可通过在对应的
view
中实现- intrinsicContentSize
方法
- (CGSize)intrinsicContentSize {
return UILayoutFittingExpandedSize;
}
2.TZImagePickerController iPhoneX适配问题
-
iPhoneX
导航条过长导致cell被覆盖问题
-
iPhoneX
图片浏览的工具条等位置问题
3.iPhoneX跳转页面时tabbar上移问题
当跳转页面的时候,只要加上
hidesBottomBarWhenPushed = YES
这行代码,当跳转页面的时候,tabbar
都会上移一下,返回的时候也是回到原位的。第一步:写一个类继承自
UITabBar
,这里我取名叫CustomTabBar
,然后在.m
文件里重写两个方法
#pragma mark - Override Methods
- (void)setFrame:(CGRect)frame
{
if (self.superview &&CGRectGetMaxY(self.superview.bounds) !=CGRectGetMaxY(frame)) {
frame.origin.y =CGRectGetHeight(self.superview.bounds) -CGRectGetHeight(frame);
}
[super setFrame:frame];
}
#pragma mark - Initial Methods
- (instancetype)initWithFrame:(CGRect)frame
{
self = [superinitWithFrame:frame];
if (self) {
self.translucent =false;
self.backgroundColor = [UIColorwhiteColor];
}
return self;
}
- 第二步:自定义
UITabBarController
取名叫TabBarVC
,在自定义的tabbar
实例化的时候,加一行代码如下:
[self setValue:[[CustomTabBar alloc]init]forKey:@"tabBar"];
4.加载 UIImagePickerController 时,图片列表被导航条遮挡
// 由于这句代码的原因
if #available(iOS 11.0, *) {
UITableView.appearance().contentInsetAdjustmentBehavior = .never
UICollectionView.appearance().contentInsetAdjustmentBehavior = .never
}
谢谢DeviceUitility
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DeviceUitility : NSObject
/// 屏幕宽度
+ (CGFloat)getDeviceScreenWidth;
/// 屏幕高度
+ (CGFloat)getDeviceScreenHeight;
/// 获取设备型号然后手动转化为对应名称
- (NSString *)getDeviceName;
/// 获取iPhone名称
+ (NSString *)getiPhoneName;
/// 获取app版本号
+ (NSString *)getAPPVerion;
/// 获取电池电量
+ (CGFloat)getBatteryLevel;
/// 当前系统名称
+ (NSString *)getSystemName ;
/// 当前系统版本号
+ (NSString *)getSystemVersion;
/// 通用唯一识别码UUID
+ (NSString *)getUUID;
// 获取当前设备IP
+ (NSString *)getDeviceIPAdress;
/// 获取精准电池电量
+ (CGFloat)getCurrentBatteryLevel;
/// 获取电池当前的状态,共有4种状态
+ (NSString *) getBatteryState;
/// 获取当前语言
+ (NSString *)getDeviceLanguage;
/// CPU总数目
+ (NSUInteger)getCPUCount;
/// 获取磁盘总空间
+ (int64_t)getTotalDiskSpace;
/// 获取未使用的磁盘空间
+ (int64_t)getFreeDiskSpace;
/// 获取已使用的磁盘空间
+ (int64_t)getUsedDiskSpace;
/// 系统总内存空间
+ (int64_t)getTotalMemory;
/// 活跃的内存,正在使用或者很短时间内被使用过
+ (int64_t)getActiveMemory;
/// 最近使用过,但是目前处于不活跃状态的内存
+ (int64_t)getInActiveMemory;
/// 空闲的内存空间
+ (int64_t)getFreeMemory;
/// 已使用的内存空间
+ (int64_t)getUsedMemory;
/// 用来存放内核和数据结构的内存,framework、用户级别的应用无法分配
+ (int64_t)getWiredMemory;
/// 可释放的内存空间:内存吃紧自动释放,针对大对象存放所需的大块内存空间
+ (int64_t)getPurgableMemory;
@end
// ----------------------------------.m----------------------------------------
#import "DeviceUitility.h"
#import <sys/utsname.h>
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <mach/mach.h>
#import <objc/runtime.h>
@implementation DeviceUitility
/// 屏幕宽度
+ (CGFloat)getDeviceScreenWidth {
return [UIScreen mainScreen].bounds.size.width;
}
/// 屏幕高度
+ (CGFloat)getDeviceScreenHeight {
return [UIScreen mainScreen].bounds.size.height;
}
// 获取设备型号然后手动转化为对应名称
- (NSString *)getDeviceName
{
// 需要#import "sys/utsname.h"
struct utsname systemInfo;
uname(&systemInfo);
NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
if ([deviceString isEqualToString:@"iPhone3,1"]) return @"iPhone 4";
if ([deviceString isEqualToString:@"iPhone3,2"]) return @"iPhone 4";
if ([deviceString isEqualToString:@"iPhone3,3"]) return @"iPhone 4";
if ([deviceString isEqualToString:@"iPhone4,1"]) return @"iPhone 4S";
if ([deviceString isEqualToString:@"iPhone5,1"]) return @"iPhone 5";
if ([deviceString isEqualToString:@"iPhone5,2"]) return @"iPhone 5 (GSM+CDMA)";
if ([deviceString isEqualToString:@"iPhone5,3"]) return @"iPhone 5c (GSM)";
if ([deviceString isEqualToString:@"iPhone5,4"]) return @"iPhone 5c (GSM+CDMA)";
if ([deviceString isEqualToString:@"iPhone6,1"]) return @"iPhone 5s (GSM)";
if ([deviceString isEqualToString:@"iPhone6,2"]) return @"iPhone 5s (GSM+CDMA)";
if ([deviceString isEqualToString:@"iPhone7,1"]) return @"iPhone 6 Plus";
if ([deviceString isEqualToString:@"iPhone7,2"]) return @"iPhone 6";
if ([deviceString isEqualToString:@"iPhone8,1"]) return @"iPhone 6s";
if ([deviceString isEqualToString:@"iPhone8,2"]) return @"iPhone 6s Plus";
if ([deviceString isEqualToString:@"iPhone8,4"]) return @"iPhone SE";
// 日行两款手机型号均为日本独占,可能使用索尼FeliCa支付方案而不是苹果支付
if ([deviceString isEqualToString:@"iPhone9,1"]) return @"iPhone 7";
if ([deviceString isEqualToString:@"iPhone9,2"]) return @"iPhone 7 Plus";
if ([deviceString isEqualToString:@"iPhone9,3"]) return @"iPhone 7";
if ([deviceString isEqualToString:@"iPhone9,4"]) return @"iPhone 7 Plus";
if ([deviceString isEqualToString:@"iPhone10,1"]) return @"iPhone_8";
if ([deviceString isEqualToString:@"iPhone10,4"]) return @"iPhone_8";
if ([deviceString isEqualToString:@"iPhone10,2"]) return @"iPhone_8_Plus";
if ([deviceString isEqualToString:@"iPhone10,5"]) return @"iPhone_8_Plus";
if ([deviceString isEqualToString:@"iPhone10,3"]) return @"iPhone_X";
if ([deviceString isEqualToString:@"iPhone10,6"]) return @"iPhone_X";
if ([deviceString isEqualToString:@"iPod1,1"]) return @"iPod Touch 1G";
if ([deviceString isEqualToString:@"iPod2,1"]) return @"iPod Touch 2G";
if ([deviceString isEqualToString:@"iPod3,1"]) return @"iPod Touch 3G";
if ([deviceString isEqualToString:@"iPod4,1"]) return @"iPod Touch 4G";
if ([deviceString isEqualToString:@"iPod5,1"]) return @"iPod Touch (5 Gen)";
if ([deviceString isEqualToString:@"iPad1,1"]) return @"iPad";
if ([deviceString isEqualToString:@"iPad1,2"]) return @"iPad 3G";
if ([deviceString isEqualToString:@"iPad2,1"]) return @"iPad 2 (WiFi)";
if ([deviceString isEqualToString:@"iPad2,2"]) return @"iPad 2";
if ([deviceString isEqualToString:@"iPad2,3"]) return @"iPad 2 (CDMA)";
if ([deviceString isEqualToString:@"iPad2,4"]) return @"iPad 2";
if ([deviceString isEqualToString:@"iPad2,5"]) return @"iPad Mini (WiFi)";
if ([deviceString isEqualToString:@"iPad2,6"]) return @"iPad Mini";
if ([deviceString isEqualToString:@"iPad2,7"]) return @"iPad Mini (GSM+CDMA)";
if ([deviceString isEqualToString:@"iPad3,1"]) return @"iPad 3 (WiFi)";
if ([deviceString isEqualToString:@"iPad3,2"]) return @"iPad 3 (GSM+CDMA)";
if ([deviceString isEqualToString:@"iPad3,3"]) return @"iPad 3";
if ([deviceString isEqualToString:@"iPad3,4"]) return @"iPad 4 (WiFi)";
if ([deviceString isEqualToString:@"iPad3,5"]) return @"iPad 4";
if ([deviceString isEqualToString:@"iPad3,6"]) return @"iPad 4 (GSM+CDMA)";
if ([deviceString isEqualToString:@"iPad4,1"]) return @"iPad Air (WiFi)";
if ([deviceString isEqualToString:@"iPad4,2"]) return @"iPad Air (Cellular)";
if ([deviceString isEqualToString:@"iPad4,4"]) return @"iPad Mini 2 (WiFi)";
if ([deviceString isEqualToString:@"iPad4,5"]) return @"iPad Mini 2 (Cellular)";
if ([deviceString isEqualToString:@"iPad4,6"]) return @"iPad Mini 2";
if ([deviceString isEqualToString:@"iPad4,7"]) return @"iPad Mini 3";
if ([deviceString isEqualToString:@"iPad4,8"]) return @"iPad Mini 3";
if ([deviceString isEqualToString:@"iPad4,9"]) return @"iPad Mini 3";
if ([deviceString isEqualToString:@"iPad5,1"]) return @"iPad Mini 4 (WiFi)";
if ([deviceString isEqualToString:@"iPad5,2"]) return @"iPad Mini 4 (LTE)";
if ([deviceString isEqualToString:@"iPad5,3"]) return @"iPad Air 2";
if ([deviceString isEqualToString:@"iPad5,4"]) return @"iPad Air 2";
if ([deviceString isEqualToString:@"iPad6,3"]) return @"iPad Pro 9.7";
if ([deviceString isEqualToString:@"iPad6,4"]) return @"iPad Pro 9.7";
if ([deviceString isEqualToString:@"iPad6,7"]) return @"iPad Pro 12.9";
if ([deviceString isEqualToString:@"iPad6,8"]) return @"iPad Pro 12.9";
if ([deviceString isEqualToString:@"AppleTV2,1"]) return @"Apple TV 2";
if ([deviceString isEqualToString:@"AppleTV3,1"]) return @"Apple TV 3";
if ([deviceString isEqualToString:@"AppleTV3,2"]) return @"Apple TV 3";
if ([deviceString isEqualToString:@"AppleTV5,3"]) return @"Apple TV 4";
if ([deviceString isEqualToString:@"i386"]) return @"Simulator";
if ([deviceString isEqualToString:@"x86_64"]) return @"Simulator";
return deviceString;
}
/// 获取iPhone名称
+ (NSString *)getiPhoneName {
return [UIDevice currentDevice].name;
}
/// 获取app版本号
+ (NSString *)getAPPVerion {
return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
}
/// 获取电池电量
+ (CGFloat)getBatteryLevel {
return [UIDevice currentDevice].batteryLevel;
}
/// 当前系统名称
+ (NSString *)getSystemName {
return [UIDevice currentDevice].systemName;
}
/// 当前系统版本号
+ (NSString *)getSystemVersion {
return [UIDevice currentDevice].systemVersion;
}
/// 通用唯一识别码UUID
+ (NSString *)getUUID {
return [[UIDevice currentDevice] identifierForVendor].UUIDString;
}
// 获取当前设备IP
+ (NSString *)getDeviceIPAdress {
NSString *address = @"an error occurred when obtaining ip address";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
success = getifaddrs(&interfaces);
if (success == 0) { // 0 表示获取成功
temp_addr = interfaces;
while (temp_addr != NULL) {
if( temp_addr->ifa_addr->sa_family == AF_INET) {
// Check if interface is en0 which is the wifi connection on the iPhone
if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
}
temp_addr = temp_addr->ifa_next;
}
}
freeifaddrs(interfaces);
return address;
}
/// 获取总内存大小
+ (long long)getTotalMemorySize {
return [NSProcessInfo processInfo].physicalMemory;
}
/// 获取当前可用内存
+ (long long)getAvailableMemorySize {
vm_statistics_data_t vmStats;
mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT;
kern_return_t kernReturn = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmStats, &infoCount);
if (kernReturn != KERN_SUCCESS)
{
return NSNotFound;
}
return ((vm_page_size * vmStats.free_count + vm_page_size * vmStats.inactive_count));
}
/// 获取精准电池电量
+ (CGFloat)getCurrentBatteryLevel {
UIApplication *app = [UIApplication sharedApplication];
if (app.applicationState == UIApplicationStateActive||app.applicationState==UIApplicationStateInactive) {
Ivar ivar= class_getInstanceVariable([app class],"_statusBar");
id status = object_getIvar(app, ivar);
for (id aview in [status subviews]) {
int batteryLevel = 0;
for (id bview in [aview subviews]) {
if ([NSStringFromClass([bview class]) caseInsensitiveCompare:@"UIStatusBarBatteryItemView"] == NSOrderedSame&&[[[UIDevice currentDevice] systemVersion] floatValue] >=6.0) {
Ivar ivar= class_getInstanceVariable([bview class],"_capacity");
if(ivar) {
batteryLevel = ((int (*)(id, Ivar))object_getIvar)(bview, ivar);
if (batteryLevel > 0 && batteryLevel <= 100) {
return batteryLevel;
} else {
return 0;
}
}
}
}
}
}
return 0;
}
/// 获取电池当前的状态,共有4种状态
+ (NSString *) getBatteryState {
UIDevice *device = [UIDevice currentDevice];
if (device.batteryState == UIDeviceBatteryStateUnknown) {
return @"UnKnow";
} else if (device.batteryState == UIDeviceBatteryStateUnplugged){
return @"Unplugged";
} else if (device.batteryState == UIDeviceBatteryStateCharging){
return @"Charging";
} else if (device.batteryState == UIDeviceBatteryStateFull){
return @"Full";
}
return nil;
}
/// 获取当前语言
+ (NSString *)getDeviceLanguage {
NSArray *languageArray = [NSLocale preferredLanguages];
return [languageArray objectAtIndex:0];
}
// CPU总数目
+ (NSUInteger)getCPUCount {
return [NSProcessInfo processInfo].activeProcessorCount;
}
// 获取磁盘总空间
+ (int64_t)getTotalDiskSpace {
NSError *error = nil;
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
if (error) return -1;
int64_t space = [[attrs objectForKey:NSFileSystemSize] longLongValue];
if (space < 0) space = -1;
return space;
}
// 获取未使用的磁盘空间
+ (int64_t)getFreeDiskSpace {
NSError *error = nil;
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
if (error) return -1;
int64_t space = [[attrs objectForKey:NSFileSystemFreeSize] longLongValue];
if (space < 0) space = -1;
return space;
}
// 获取已使用的磁盘空间
+ (int64_t)getUsedDiskSpace {
int64_t totalDisk = [self getTotalDiskSpace];
int64_t freeDisk = [self getFreeDiskSpace];
if (totalDisk < 0 || freeDisk < 0) return -1;
int64_t usedDisk = totalDisk - freeDisk;
if (usedDisk < 0) usedDisk = -1;
return usedDisk;
}
// 系统总内存空间
+ (int64_t)getTotalMemory {
int64_t totalMemory = [[NSProcessInfo processInfo] physicalMemory];
if (totalMemory < -1) totalMemory = -1;
return totalMemory;
}
// 活跃的内存,正在使用或者很短时间内被使用过
+ (int64_t)getActiveMemory {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.active_count * page_size;
}
// 最近使用过,但是目前处于不活跃状态的内存
+ (int64_t)getInActiveMemory {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.inactive_count * page_size;
}
// 空闲的内存空间
+ (int64_t)getFreeMemory {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.free_count * page_size;
}
// 已使用的内存空间
+ (int64_t)getUsedMemory {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return page_size * (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count);
}
// 用来存放内核和数据结构的内存,framework、用户级别的应用无法分配
+ (int64_t)getWiredMemory {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.wire_count * page_size;
}
// 可释放的内存空间:内存吃紧自动释放,针对大对象存放所需的大块内存空间
+(int64_t)getPurgableMemory {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.purgeable_count * page_size;
}
@end