Xcode9新特性/iOS11适配-收编
2017-10-19 本文已影响518人
百草纪
更新中......(部分省略)
10.19已更新
10.20已更新
11.4 已更新
- 文章推荐:
Xcode9新特性
1.启动多个模拟器
方案一
- 从
Xcode
选择不同的模拟器,启动新的模拟器。方案二
- 从模拟器
menu
上的Hardware
---Device
,选择新的模拟器启动。
u=2475746809,941184978&fm=173&s=00095C320EB7729A8761914D0300B0F1&w=640&h=455&img.JPEG
2.WiFi无线安装App
- 操作的步骤如下(注意:必须是
iOS11
,iPhone
和Mac
处于同一WiFi
下。):- 接线连接
iPhone
。点选Xcode
menu
的Window
,选择Devices and Simulators
。 - u=2364080816,4230627080&fm=173&s=C801CC1A215C6DCC0ADDC9DB0100C0B2&w=640&h=399&img.JPEG
- 勾选
Connect via network
,连线到iPhone
。如果连线顺利,iPhone
旁会出现如下选项。 - u=1977584014,4032251507&fm=173&s=E010693A53BFF9EB087D98C30100A0B0&w=640&h=489&img.JPEG
- 如果刚刚没有出现网路图示,或是拔线后,
iPhone
不理我们,在Devices and Simulators
视窗显示Disconnected
。此时Xcode
找不到iPhone
,也就无法顺利安装App
。 - u=3864239553,1403343358&fm=173&s=70C2D81A2F7A5E09104780D2030010BA&w=488&h=262&img.JPEG
- 在
Devices and Simulators
视窗上选择iPhone
后,从右键选单点选Connect via IP Address
,输入iPhone
的IP
后,点选Connect
连线。 - u=4111917007,1633424150&fm=173&s=3076C83297C875414EEF1DCC0300E0B0&w=639&h=263&img.JPEG
- IP 地址,则可从
iPhone
设定App
的WiFi
页面查询。
- 接线连接
3.错误提示
- 错误可以多行显示,
Fix
会自动出现,点选即可修正问题。 - u=3931270588,1281757378&fm=173&s=0FC4FD17CFE47C03565591F40300503E&w=640&h=187&img.JPEG
4.按住 command
加+
可将代码放大,command
加-
可将代码縮小。
5.提示选单
- 將鼠标移到
{ }
、( )
或是class
、func
、if
、for
等关键字,按住command
建,Xcode
將表示对应的class
、function
、if
、for
代码块。- 鼠标移到方法上,按
command
建,会出现提示选单。 - Snip20171017_1.png
- 按住
command
建再点击Jump To Definition
,跳到方法的定义。 - 如果想利用快速建跳到定义,按住
command + control
再点击。 - 回到以前的样子:
- 20170922150758282.png
- 鼠标移到方法上,按
- 介绍:
-
Jump to Definition
跳转到定义的方法 -
Fold
折叠方法 -
Rename
重命名
-
6.swift
重新命名、自动补全协议的required方法,Extract Method
自动提取方法
swift
重新命名- u=4067943835,489730897&fm=173&s=811EED3280E079015255CCC60300F0B3&w=639&h=221&img.JPEG
- u=2013514408,4020135435&fm=173&s=401AE032515E45CC4E5121DA000080B2&w=639&h=528&img.JPEG
- u=3062817103,696550176&fm=173&s=4018EC32511ED5CC1E5160DB0000D0B2&w=640&h=540&img.JPEG
Extract Method
自动提取方法- Snip20171018_1.png
- Snip20171018_2.png
7.深度整合 github
- 将
Xcode
的代码上传到github
-
以前:先在
github
上建立远程仓库,然后再在Xcode
中设置远程仓库,最后执行push
上传。 -
现在:先本地
git
初始化代码,进行git
管理。 - 再在打开项目的工具条选择第二个图标,选择
Create Remote...
- u=458925110,1703897494&fm=173&s=F190CB38114E7549106984DE0300D0B3&w=640&h=468&img.JPEG
- 填写信息
- u=3554539748,1548131435&fm=173&s=08887432119FE5CE4A6100DB0000D0B3&w=640&h=548&img.JPEG
-
以前:先在
8.给顏色添加名字
-
Assets.xcassets
现在除了加入图片,还可以加入有名字的颜色,方便我们之后在Storyboard
或程式里使用。 - u=3651431358,4056156254&fm=173&s=81025D32110F754D02D0B4C80100F0B3&w=640&h=654&img.JPEG
- 可以在
Storyboard
控件选择颜色时,在Named Colors
下看到我們取的顏色名字。 -
[UIColor colorNamed:@"Color"]
iOS11新方法
9.新的编译系统
- 新的编译器已经用
Swift
重写了,性能得到了很大的提升。 - 1452146-1cd1541b5b6e291b.jpg
10.Finder
和 Simulator
共享文件
-
Simulator
具有Finder
扩展,我们可以直接从Finder
窗口共享文件给Simulator
. - Snip20171018_5.png
11.折叠代码
20170926164432230.jpeg- 菜单的
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 为安全区域 - 1944396-07171b00b426320f.png
-
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
,大字标题如下图 - 968977-89a88f618da51832.png
- 968977-b19a09df0a51bf50.png
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
Snip20171019_7.pngSnip20171019_8.png
Snip20171019_9.png
2.
Snip20171019_12.pngSnip20171019_11.png
Snip20171019_10.png
3.
Snip20171019_14.pngSnip20171019_13.png
4.
Snip20171019_15.pngSnip20171019_16.png
Snip20171019_18.png
Snip20171019_21.png
Snip20171019_20.png
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被覆盖问题
Snip20171020_1.png
-
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