iOS阻止文件被iTunes和iCloud同步

iCloud 会通过WiFi每天自动备份用户iOS设备。除了应用Bundle本身、Caches目录和tmp目录,app目录下的所有东西都会被备份。由于备份通过WiFi进行,并且为每个用户存储在iCloud中,应用需*小化自己存储的数据数量。大文件会延长备份时间,并且消耗用户的可用iCloud空间。

为了确保备份尽可能快速高效,应用存储数据需要遵循以下指导方针:

1. 只有那些用户生成的文档或其它数据,或者应用不能重新创建的数据,才应该存储在/Documents目录下,并且会被自动备份到iCloud。

2. 可以重新下载或生成的数据,应该存储在/Library/Caches目录。例如数据库缓存文件、可下载文件(杂志、报纸、地图应用使用的数据)等都属于这一类。

3. 临时使用的数据应该存放在/tmp目录。尽管这些文件不会被iCloud备份,应用在使用完之后需要记得删除这些文件,这样才不会继续占用用户设备的空间。

4. 使用”不要备份”属性来指定那些需要保留在设备中的文件(即使是低存储空间情况下)。那些能够重新生成,但在低存储空间时仍需保留,对应用正常运行有影响,或者用户希望文件在离线时可用的文件,需要使用这个属性。无论哪个目录下的文件(包括Documents目录),都可以使用这个属性。这些文件不会被删除,也不会包含在用户的iCloud或iTunes备份中。由于这些文件一直占用着用户设备的存储空间,应用有责任定期监控和删除这些文件。

iOS 5.0.1开始支持”do not backup”文件属性(com.apple.MobileBackup),允许开发者明确地指定哪些文件应该被备份,哪些是本地缓存可以自动删除,哪些文件不需要备份但不能删除。此外,对目录设置这个属性,会阻止备份该目录和目录中的所有内容。

文件可以分为以下四种数据类型:

关键数据
这些是用户创建的数据,或其它不能重新生成的数据。应该存放在/Documents目录下,并且不应该标记为”do not backup”属性。关键数据在低存储空间时也会保留,而且会被iCloud或iTunes备份。

路径:/Documents

属性:不要设置”不备份”

管理:iOS系统即时遇到存储空间不足的情况下,也不会清除,同时会备份到iTunes或iCloud中

缓存数据
可以重新下载或生成的数据,而且没有这些数据也不会妨碍用户离线使用应用的功能。缓存数据应该保存在/Library/Caches目录下。缓存数据在设备低存储空间时可能会被删除,iTunes或 iCloud不会对其进行备份。

路径:/Library/Caches

属性:默认

管理:在存储空间不足的情况下,会清空, 并且不会被自动备份到iTunes和iCloud中

临时数据
应用需要写到本地存储,内部使用的临时数据,但不需要长期保留使用。临时数据应该保存在/tmp目录。系统可能会清空该目录下的数据,iTunes或iCloud也不会对其进行备份。应用在不需要使用这些数据时,应该尽快地删除临时数据,以避免浪费用户的存储空间

路径:/tmp

属性:默认

管理:随时可能被iOS系统清除,且不会自动备份到iTunes和iCloud,尽量在文件不再使用时应用自己清空,避免对用户设备空间的浪费

离线数据
可以下载或重新创建,但用户希望在离线时也能访问这些数据。离线数据应该存放在/Documents目录或/Library/Private Documents目录,并标记为”do not backup”属性。这两个位置的数据在低存储空间时都会保留,而”do not backup”属性会阻止iTunes或iCloud备份。应用不再需要离线数据文件时,应该尽快删除,以避免浪费用户的存储空间。

路径:/Documents  或 /Library/自定义的文件夹

属性:放于Documents下不需设置,放在自定义文件夹中需设置”不备份”

管理:与关键数据类似,即时在存储空间不足的情况下也不会清除,应用自己应该清除已经不再使用的文件,以免浪费用户设备空间

设置Do Not Backup扩展属性
#import “sys/xattr.h”

– (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)url {
const char* filePath = url.path.fileSystemRepresentation;
const char* attrName = “com.apple.MobileBackup”;
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;

 

iOS14适配兼容

Cell点击无效
在iOS14上可能出现点击cell上的视图无法响应的情况.
原因:

iOS14更改Cell视图布局.将contentView放在*上层,如果将视图加载在cell上,将会出现contentView遮罩,导致事件无法响应.是在此前关于 contentView 的声明注释中,官方已经明确建议开发者将 customView 放在 contentView 上,使 contentView 作为 UITableViewCell 默认的父视图。

解决办法:
1、可以将cell子视图加载在contentView上(提倡)
2、将contentView设置到*底层 self.sendSubviewToBack(self.contentView)

UIDatePicker 更新 UI 样式
iOS14 UIDatePicker新增加了一个UI样式 UIDatePickerStyleInline 作为默认样式,如果还需要旧版本的滚轮样式,需要设置为

UIDatePicker 的 preferredDatePickerStyle 属性为 UIDatePickerStyleWheels。

typedef NS_ENUM(NSInteger, UIDatePickerStyle) {
/// Automatically pick the best style available for the current platform & mode.
UIDatePickerStyleAutomatic,
/// Use the wheels (UIPickerView) style. Editing occurs inline.
UIDatePickerStyleWheels,
/// Use a compact style for the date picker. Editing occurs in an overlay.
UIDatePickerStyleCompact,
/// Use a style for the date picker that allows editing in place.
UIDatePickerStyleInline API_AVAILABLE(ios(14.0)) API_UNAVAILABLE(tvos, watchos),
} API_AVAILABLE(ios(13.4)) API_UNAVAILABLE(tvos, watchos);
相册权限
iOS14 新增了“Limited Photo Library Access” 模式,在授权弹窗中增加了 Select Photo 选项。用户可以在 App 请求调用相册时选择部分照片让 App 读取。从 App 的视⻆来看,你的相册里就只有这几张照片,App 无法得知其它照片的存在。
权限提示框会在每次冷启动后打开相册时重新弹出,可以在 info.plist 中设置 PHPhotoLibraryPreventAutomaticLimitedAccessAlert 选项为 YES ,关闭提示。

在 iOS14 中官方推荐使用 PHPicker 来替代原 API 进行图片选择。PHPicker 为独立进程,会在视图*顶层进行展示,应用内无法对其进行截图也无法直接访问到其内的数据。

UIImagePickerController -> PHPickerViewController, UIImagePickerViewController 功能受限,每次只能选择一张图片,将逐渐被废弃。

地理位置
CLLocationManager 新增了 精确定位 和 模糊定位 的概念,用户可以手动选择,模糊定位的误差约 500m 。可以根据实际功能判断是否可以接受用户选择模糊定位。

如果功能强依赖精确定位,可以在需要的时候调用 requestTemporaryFullAccuracyAuthorizationWithPurposeKey 方法。

– (void)requestTemporaryFullAccuracyAuthorizationWithPurposeKey:(NSString *)purposeKey completion:(void(^ _Nullable)(NSError * _Nullable))completion;

– (void)requestTemporaryFullAccuracyAuthorizationWithPurposeKey:(NSString *)purposeKey;
单独请求一次精确定位,用户可以选择拒*授权。所需参数 purposeKey 需要在 info.plist 中设置 NSLocationTemporaryUsageDescriptionDictionary 字典。

可以通过 accuracyAuthorization 属性获取当前的定位方式:

@property (nonatomic, readonly) CLAccuracyAuthorization accuracyAuthorization;
typedef NS_ENUM(NSInteger, CLAccuracyAuthorization) {
// 精准定位
CLAccuracyAuthorizationFullAccuracy,
// 模糊定位
CLAccuracyAuthorizationReducedAccuracy,
};
适配UIPageControl
iOS14以后删除了pageImage 与currentPageImage,不能再通过KVC修改控制器的图片。

解决方案:

借助iOS14新增字段preferredIndicatorImage,我们可以修改指示器小圆点的大小以及形状,借助currentPageIndicatorTintColor与pageIndicatorTintColor来确认不同状态下小圆点的颜色。

*终展示的颜色是由TintColor以及preferredIndicatorImage共同决定的,因此这里将preferredIndicatorImage设置为白色。

使用layer.mask做遮罩时无法显示
使用UIImageView的layer 做遮罩时,不显示任何东西。

在iOS14以下使用UIImageView的layer做遮罩的代码:

UIImageView *maskView = [[UIImageView alloc] initWithImage:maskImage];
maskView.frame = self.bounds;
self.layer.mask = maskView.layer;
但是在iOS14上无法正常展示。

解决方案:

UIImage *newImage = [self stretchImage:maskImage newSize:self.bounds.size leftCapWidth:maskImage.size.width/2 topCapHeight:maskImage.size.height-7];
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = self.bounds;
maskLayer.contents = (id)newImage.CGImage;
self.layer.mask = maskLayer;
– (UIImage *)stretchImage:(UIImage *)originImage newSize:(CGSize)newSize leftCapWidth:(CGFloat)leftCapWidth topCapHeight:(CGFloat)topCapHeight{
UIImage *newImage;
newImage = [originImage stretchableImageWithLeftCapWidth:leftCapWidth topCapHeight:topCapHeight];
UIGraphicsBeginImageContextWithOptions(newSize, false, 0);
[newImage drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];

newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;

 

iOS时间格式化输出技巧

一.前言
*近项目开发过程中用到了大量的关于时间的处理,将后台返回的时间字符串转换为指定的格式时间再显示在UI上.

例如: 将后台返回的时间字符串 2017-04-16 13:08:06 转换为:2017年04月16日、2017年04月、04月16日、2017-04-16、2017-04、04-16、13:08、星期几等等.

项目是多人开发,由于前期没有统一处理时间转换的问题,后期发现项目中好多关于时间转换的代码,大部分都是通过(- : 等字符)截取成字符串数组再取相应时间拼接成指定格式,输出在UI显示的地方,代码非常的臃肿,并且这种方式非常不可取.

原因:后台返回的时间字符串 并不都是 2017-04-16 13:08:06这种格式,还有2017-04-16这种格式,截取前需要长度格式等校验,多了很多校验代码.非常不可取.

既然是时间,我们便要通过时间的思维来完成转换问题,不要通过截取字符串的方式

于是我便写了一个类,来统一处理转换问题.

代码地址:见片尾

二.效果
Demo.png

具体怎么操作:

三.将时间字符串->NSDate
首先我们要将2017-04-16 13:08:06或2017-04-16这种格式时间字符串转换为NSDate

我们新建一个NSDate的Category,笔者取名为NSDate+XHCategory,写一个时间字符串->NSDate方法,代码如下:

+(NSDate*)xh_dateWithFormat_yyyy_MM_dd_HH_mm_ss_string:(NSString )string
{
NSDateFormatter dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@“yyyy-MM-dd HH:mm:ss”];
NSDate *date =[dateFormat dateFromString:string];
return date;
}

为了兼用其他格式时间字符串,我们把可能的情况都写上,如下

+(NSDate *)xh_dateWithFormat_yyyy_MM_dd_HH_mm_string:(NSString )string
{
NSDateFormatter dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@“yyyy-MM-dd HH:mm”];
NSDate *date =[dateFormat dateFromString:string];
return date;
}

+(NSDate *)xh_dateWithFormat_yyyy_MM_dd_HH_string:(NSString )string
{
NSDateFormatter dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@“yyyy-MM-dd HH”];
NSDate *date =[dateFormat dateFromString:string];
return date;
}

+(NSDate *)xh_dateWithFormat_yyyy_MM_dd_string:(NSString )string
{
NSDateFormatter dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@“yyyy-MM-dd”];
NSDate *date =[dateFormat dateFromString:string];
return date;
}

+(NSDate *)xh_dateWithFormat_yyyy_MM_string:(NSString )string
{
NSDateFormatter dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@“yyyy-MM”];
NSDate *date =[dateFormat dateFromString:string];
return date;
}

再写一个统一转换时间字符串为 NSDate的方法,如下:

+(NSDate *)xh_dateWithDateString:(NSString *)dateString
{
NSDate *date = nil;
date = [self xh_dateWithFormat_yyyy_MM_dd_HH_mm_ss_string:dateString];
if(date) return date;
date = [self xh_dateWithFormat_yyyy_MM_dd_HH_mm_string:dateString];
if(date) return date;
date = [self xh_dateWithFormat_yyyy_MM_dd_HH_string:dateString];
if(date) return date;
date = [self xh_dateWithFormat_yyyy_MM_dd_string:dateString];
if(date) return date;
date = [self xh_dateWithFormat_yyyy_MM_string:dateString];
if(date) return date;
return nil;
}

四.将NSDate -> NSDateFormatter
为什么要再转换为NSDateFormatter,有些人可能已经明白了,我们点开NSDateFormatter可以看到NSDateFormatter有以下属性

@property (nullable, copy) NSCalendar *calendar NS_AVAILABLE(10_7, 4_0);
@property (nullable, copy) NSTimeZone *timeZone NS_AVAILABLE(10_7, 4_0);
@property NSInteger era;
@property NSInteger year;
@property NSInteger month;
@property NSInteger day;
@property NSInteger hour;
@property NSInteger minute;
@property NSInteger second;
@property NSInteger nanosecond NS_AVAILABLE(10_7, 5_0);
@property NSInteger weekday;
@property NSInteger weekdayOrdinal;
@property NSInteger quarter NS_AVAILABLE(10_6, 4_0);
@property NSInteger weekOfMonth NS_AVAILABLE(10_7, 5_0);
@property NSInteger weekOfYear NS_AVAILABLE(10_7, 5_0);
@property NSInteger yearForWeekOfYear NS_AVAILABLE(10_7, 5_0);
@property (getter=isLeapMonth) BOOL leapMonth NS_AVAILABLE(10_8, 6_0);
@property (nullable, readonly, copy) NSDate *date NS_AVAILABLE(10_7, 4_0);

@end

我们新建一个NSDateComponents 的Category,笔者取名NSDateComponents+XHCategory,并实现如下方法:

+(NSDateComponents *)xh_dateComponentsFromDate:(NSDate *)date
{
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear| NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekOfYear | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal fromDate:date];
return components;

}

接着我们就可以进行转换操作了,我们新建一个NSString的Category,笔者取名NSString+XHDateFormat

在NSString+XHDateFormat.h文件中写上需要转换的类型如下:

/**

x年x月x日
*/
@property(nonatomic,copy,readonly)NSString *xh_formatNianYueRi;
/**

x年x月
*/
@property(nonatomic,copy,readonly)NSString *xh_formatNianYue;
/**

x月x日
*/
@property(nonatomic,copy,readonly)NSString *xh_formatYueRi;
/**

x年
*/
@property(nonatomic,copy,readonly)NSString *xh_formatNian;
/**

x时x分x秒
*/
@property(nonatomic,copy,readonly)NSString *xh_formatShiFenMiao;
/**

x时x分
*/
@property(nonatomic,copy,readonly)NSString *xh_formatShiFen;
/**

x分x秒
*/
@property(nonatomic,copy,readonly)NSString *xh_formatFenMiao;
/**

yyyy-MM-dd
*/
@property(nonatomic,copy,readonly)NSString *xh_format_yyyy_MM_dd;
/**

yyyy-MM
*/
@property(nonatomic,copy,readonly)NSString *xh_format_yyyy_MM;
/**

MM-dd
*/
@property(nonatomic,copy,readonly)NSString *xh_format_MM_dd;
/**

yyyy
*/
@property(nonatomic,copy,readonly)NSString *xh_format_yyyy;
/**

HH:mm:ss
*/
@property(nonatomic,copy,readonly)NSString *xh_format_HH_mm_ss;
/**

HH:mm
*/
@property(nonatomic,copy,readonly)NSString *xh_format_HH_mm;
/**

mm:ss
*/
@property(nonatomic,copy,readonly)NSString *xh_format_mm_ss;
#pragma mark – 转换为星期几
@property(nonatomic,copy,readonly)NSString *xh_formatWeekDay;

在 NSString+XHDateFormat.m 实现如下:

-(NSString *)xh_formatNianYueRi
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld年%02ld月%02ld日”,date.year,date.month,date.day];
}
-(NSString *)xh_formatNianYue
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld年%02ld月”,date.year,date.month];
}
-(NSString *)xh_formatYueRi
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%02ld月%02ld月”,date.month,date.day];
}
-(NSString *)xh_formatNian
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld年”,date.year];
}
-(NSString *)xh_formatShiFenMiao
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld时%02ld分%02ld秒”,date.hour,date.minute,date.seconds];
}
-(NSString *)xh_formatShiFen
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld时%02ld分”,date.hour,date.minute];
}
-(NSString *)xh_formatFenMiao
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%02ld分%02ld秒”,date.minute,date.seconds];
}
-(NSString *)xh_format_yyyy_MM_dd
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld-%02ld-%02ld”,date.year,date.month,date.day];
}
-(NSString *)xh_format_yyyy_MM
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld-%02ld”,date.year,date.month];
}
-(NSString *)xh_format_MM_dd
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%02ld-%02ld”,date.month,date.day];
}
-(NSString *)xh_format_yyyy
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%ld”,date.year];
}
-(NSString *)xh_format_HH_mm_ss
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%02ld:%02ld:%02ld”,date.hour,date.minute,date.seconds];
}
-(NSString *)xh_format_HH_mm
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%02ld:%02ld”,date.hour,date.minute];
}
-(NSString *)xh_format_mm_ss
{
NSDate *date = [NSDate xh_dateWithDateString:self];
return [NSString stringWithFormat:@”%02ld:%02ld”,date.minute,date.seconds];
}

-(NSString *)xh_formatWeekDay
{
NSString *weekStr=nil;
NSDate *date = [NSDate xh_dateWithDateString:self];
switch (date.weekday) {
case 2:
weekStr = @“星期一”;
break;
case 3:
weekStr = @“星期二”;
break;
case 4:
weekStr = @“星期三”;
break;
case 5:
weekStr = @“星期四”;
break;
case 6:
weekStr = @“星期五”;
break;
case 7:
weekStr = @“星期六”;
break;
case 1:
weekStr = @“星期天”;
break;
default:
break;
}
return weekStr;
}

五.调用:
self.timeString = @”2017-04-16 13:08:06″;

//星期
NSString *time0 = self.timeString.xh_formatWeekDay;

//2017年04月16日
NSString *time1 = self.timeString.xh_formatNianYueRi;

//2017年04月
NSString *time2 = self.timeString.xh_formatNianYue;

//04月16日
NSString *time3 = self.timeString.xh_formatYueRi;

//2017年
NSString *time4 = self.timeString.xh_formatNian;

//13时08分01秒
NSString *time5 = self.timeString.xh_formatShiFenMiao;

//13时08分
NSString *time6 = self.timeString.xh_formatShiFen;

//08分01秒
NSString *time7 = self.timeString.xh_formatFenMiao;

//2017-04-16
NSString *time8 = self.timeString.xh_format_yyyy_MM_dd;

//2017-04
NSString *time9 = self.timeString.xh_format_yyyy_MM;

//04-16
NSString *time10 = self.timeString.xh_format_MM_dd;

//2017
NSString *time11 = self.timeString.xh_format_yyyy;

//13:08:06
NSString *time12 = self.timeString.xh_format_HH_mm_ss;

//13:08
NSString *time13 = self.timeString.xh_format_HH_mm;

//08:06
NSString *time14 = self.timeString.xh_format_mm_ss;
————————————————
版权声明:本文为CSDN博主「小小兵的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38987922/article/details/115321152

iOS14隐私权限适配及其他

Overview

在WWDC2020发布会上苹果展示了新的iOS14系统。对于iOS开发工程师来说,适配iOS14其重点在于隐私权限的适配。具体内容可以观看WWDC2020中:建立更好的隐私信任的视频进行了解。

note:截止目前,适配iOS14需要更新mac系统到11 beta 6、xcode需要更新到12 beta 6、手机需要更新到14 beta 8,相关版本可以到苹果官网下载;更新beta版本打包可能会影响正常上架,该问题未进行测试,但需要引起注意。

广告标识符的获取

广告标识符(Identity for Advertisers)简称IDFA,主要用来标记用户。在iOS14系统中,系统会默认关闭广告标跟踪权限。如果在开发中使用,需要向用户请求权限,步骤如下:

1、info.plist配置

选中info.plist右键Open As->Source Code 然后将下方配置和描述信息添加进去。

 

  1. <key>NSUserTrackingUsageDescription</key>
  2. <string>“太平通宝”需要您允许访问广告标识符权限,以便于追踪广告和信息的推送</string>

2、头文件引入

为了适配低版本Xcode编译,需要使用预编译命令,所以头文件引入方式如下所示:

 

  1. #if defined(__IPHONE_14_0)
  2. #import <AppTrackingTransparency/AppTrackingTransparency.h>//适配iOS14
  3. #endif

3、获取IDFA

iOS14及以上系统,需要先请求跟踪权限,用户同意后才能获取广告标识。获取方法标识符的代码iOS14之前一样。示例代码如下所示:

 

  1. + (NSString *)idfaString {
  2. __block NSString *idfa;
  3. #if defined(__IPHONE_14_0)
  4. if (@available(iOS 14, *)) {
  5. // iOS14及以上版本需要先请求权限
  6. ATTrackingManagerAuthorizationStatus status = ATTrackingManager.trackingAuthorizationStatus;
  7. if (status == ATTrackingManagerAuthorizationStatusNotDetermined) { //用户未做选择或未弹窗
  8. dispatch_semaphore_t sem = dispatch_semaphore_create(0);
  9. [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
  10. // 获取到权限后,依然使用老方法获取idfa
  11. if (status == ATTrackingManagerAuthorizationStatusAuthorized) { //用户允许
  12. idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
  13. ICLog(@”–iOS14—-%@—-“,idfa);
  14. }
  15. dispatch_semaphore_signal(sem);
  16. }];
  17. dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
  18. }else if(status == ATTrackingManagerAuthorizationStatusAuthorized){//用户允许
  19. idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
  20. }else{
  21. ICLog(@”请在设置-隐私-Tracking中允许App请求跟踪”);
  22. }
  23. }
  24. #else
  25. // iOS14以下版本依然使用老方法
  26. // 判断在设置-隐私里用户是否打开了广告跟踪
  27. if ([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]) {
  28. idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
  29. ICLog(@”—iOS14以下系统—-%@—–“,idfa);
  30. } else {
  31. ICLog(@”请在设置-隐私-广告中打开广告跟踪功能”);
  32. }
  33. #endif
  34. idfa = (idfa ? : @””);
  35. return idfa;
  36. }

相册权限

iOS14中新增了个有限的图片库访问模式,在授权弹窗的时候会新增个Select Photo选项,用户可以选择一部分图片供App读取,而App无法获取相册中的所有图片信息。

如果用户使用了有限图片库访问(Limited Photo Library Access)的模式, 如果App不进行适配,权限提示框会在每次冷启动打开相册的时候重新弹出,我们需要在info.plist中进行配置,关闭弹窗。

1、info.plist配置

选中info.plist右键Open As->Source Code 然后将下方配置和描述信息添加进去。

 

  1. <key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
  2. <true/>

当然,我们也可以通过相应API来控制何时弹出图片选择的弹出。API如下所示:

 

[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];

同时,在iOS14中官方推荐使用苹果推荐使用PHPicker来代替原API来选择图片。

关于PHPicker的介绍可以参看WWDC2020:认识新的照片选择器的相关介绍。

位置信息

在iOS14中,苹果新增了模糊定位的概念。原因是苹果认为很多APP并不需要获取用户的精准定位。所以在iOS14授权弹窗的时候新增了Precise的精准开关,默认会选中精准位置,用户可以通过这个开关进行更改。

对于地理位置敏感的APP

1、info.plist配置

不过对于需要精准定位的App需要在info.plist中设置NSLocationTemporaryUsageDescriptionDictionary字典,key为purposeKey,value为对应获取精准定位的原因。

示例如下:

 

  1. <key>NSLocationTemporaryUsageDescriptionDictionary</key>
  2. <dict>
  3. <key>punchTheClock</key>
  4. <string>“太平通宝”需要您允许精准定位,以便于使用打卡功能</string>
  5. </dict>

2、获取单次精准定位

同时需要调用相应API,获取精准定位。代码如下:

 

[CALocationMnanger requestTemporaryFullAccuracyAuthorizationWithPurposeKey:@"punchTheClock"]

对于地理位置不敏感的App

对定位信息不敏感的APP,iOS14中可以直接在info.plist中添加NSLocationDefaultAccuracyReducedtrue,默认请求模糊定位

选中info.plist右键Open As->Source Code 然后将下方配置和描述信息添加进去。

 

  1. <key>NSLocationDefaultAccuracyReduced</key>
  2. <true/>

Local Network

iOS14中新增了Local Network权限提示,具体关于Local Network的相关信息可以查看苹果官网的视频或者少数派的关于iOS14新增的本地网络权限,要开给第三方App吗?等相关资料。

剪贴板

在iOS14中,如果APP读取剪切版的内容时,手机会弹出提示,提示哪个APP在获取剪切板内容。

相机和麦克风

在iOS14中APP如果使用相机和麦克风,手机的的上方会有绿色和黄色的提示,同时也可以查看是哪个APP在使用相机和麦克风。

关于该功能开发人员无法控制。

UIDatePicker更新UI样式

在iOS14中,UIDatePicker的样式新增了UIDatePickerStyleInline,而且为默认值。如果项目中使用了UIDatePicker,而且希望使用原来的样式,需要设置其样式。

 

 self.pickerView.preferredDatePickerStyle = UIDatePickerStyleWheels;

UITableViewCell适配

UITableViewCell无法点击

在Xcode12、iOS14中,如果在UITableViewCell渲染前没有调用self.contentView,系统会在渲染完UITableViewCell上的控件后在其上方添加contentView,这会使contentView拦截住UITableViewCell控件的响应事件。

其解决方式是将UITableViewCell上的控件添加到self.contentView

 

  1. [self addSubview:view];
  2. 改为:
  3. [self.contentView addSubview:view];

hook修复UITableViewCell无法点击问题

虽然上方的方法可以修复UITableViewCell无法点击问题,但对于一个很庞大的项目来说,不确定是否有遗漏,尤其是一些组件。所以在项目中需要用到修改+hook的方式。

方法也很简单,直接hook住UITableViewCell中的addSubview:方法,全局修复下即可,同时后期写代码也要注意代码规范。

 

  1. #import “UITableViewCell+TB.h”
  2. #import <objc/runtime.h>
  3. @implementation UITableViewCell (TB)
  4. + (void)load {
  5. Method method1 = class_getInstanceMethod([self class], NSSelectorFromString(@”addSubview:”));
  6. Method method2 = class_getInstanceMethod([self class], @selector(tb_addSubview:));
  7. method_exchangeImplementations(method1, method2);
  8. }
  9. – (void)addSubview:(UIView *)view{
  10. [super addSubview:view];
  11. }
  12. – (void)tb_addSubview:(UIView *)view {
  13. if ([view isKindOfClass:NSClassFromString(@”UITableViewCellContentView”)]) {
  14. [self tb_addSubview:view];
  15. } else {
  16. [self.contentView addSubview:view];
  17. }
  18. }
  19. @end

UITableViewCell 背景色变成灰色

灰色为self.contentView的背景色,在init方法中共添加即可。

YYAnimatedImageView 无法加载图片

因为项目中用到YYImage第三方库。

解决方式:
修复:YYAnimatedImageView.m 529行的函数修改如下:

 

  1. – (void)displayLayer:(CALayer *)layer {
  2. if (_curFrame) {
  3. layer.contents = (__bridge id)_curFrame.CGImage;
  4. }else {
  5. if (@available(iOS 14.0, *)) {
  6. [super displayLayer:layer];
  7. }
  8. }
  9. }

但在项目中,并不会这些修复,毕竟是第三方库,我们可以直接替换这个类的该方法。

代码如下:

 

  1. #import “YYAnimatedImageView+TB.h”
  2. #import <objc/runtime.h>
  3. @implementation YYAnimatedImageView (TB)
  4. + (void)load {
  5. Method method1 = class_getInstanceMethod([self class], NSSelectorFromString(@”displayLayer:”));
  6. Method method2 = class_getInstanceMethod([self class], @selector(tb_displayLayer:));
  7. method_exchangeImplementations(method1, method2);
  8. }
  9. – (void)tb_displayLayer:(CALayer *)layer{
  10. Ivar ivar = class_getInstanceVariable(self.class, “_curFrame”);
  11. UIImage *_curFrame = object_getIvar(self, ivar);
  12. if (_curFrame) {
  13. layer.contents = (__bridge id)_curFrame.CGImage;
  14. }else{
  15. if (@available(iOS 14.0, *)) {
  16. [super displayLayer:layer];
  17. }
  18. }
  19. }
  20. @end

写在*后

关于真机调试

*新Xcode 12 beta版本31G,而且还不稳定,如果需要使用低版本Xcode运行到iOS14的真机上可以下载iOS14的DeviceSupport,存放的路径为:

 

  1. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

关于更新iOS14系统

关于更新iOS14 beta版的系统,我在百度经验上水了篇文章,可以点击百度经验查看,当然经验水的有些粗糙,还有错别字。

也可能是好久没写了,写完后,竟然还给了0.3元的红包……

IOS学习之 plist文件的读写

在做IOS开发时,经常用到到plist文件, 那plist文件是什么呢? 它全名是:Property List,属性列表文件,它是一种用来存储串行化后的对象的文件。属性列表文件的扩展名为.plist,因此通常被称为plist文件。文件是xml格式的。

Plist文件通常用于储存用户设置,也可以用于存储捆绑的信息

我们创建一个项目来学习plist文件的读写。

1、创建项目Plistdemo

项目创建之后可以找到项目对应的plist文件,打开如下图所示:

%title插图%num%title插图%num

在编辑器中显示类似与表格的形式,可以在plist上右键,用源码方式打开,就能看到plist文件的xml格式了。

2、创建plist文件。

按command +N快捷键创建,或者File —> New —> New File,选择Mac OS X下的Property List

%title插图%num%title插图%num

%title插图%num

%title插图%num

创建plist文件名为plistdemo。

打开plistdemo文件,在空白出右键,右键选择Add row 添加数据,添加成功一条数据后,在这条数据上右键看到valueType选择Dictionary。点加号添加这个Dictionary下的数据

%title插图%num%title插图%num

添加完key之后在后面添加Value的值,添加手机号和年龄

创建完成之后用source code查看到plist文件是这样的:

<?xml version=”1.0″ encoding=”UTF-8″?> <!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”> <plist version=”1.0″> <dict> <key>jack</key> <dict> <key>phone_num</key> <string>13801111111</string> <key>age</key> <string>22</string> </dict> <key>tom</key> <dict> <key>phone_num</key> <string>13901111111</string> <key>age</key> <string>36</string> </dict> </dict> </plist>

3、读取plist文件的数据

现在文件创建成功了,如何读取呢,实现代码如下:
– (void)viewDidLoad { [super viewDidLoad]; //读取plist NSString *plistPath = [[NSBundle mainBundle] pathForResource:@”plistdemo” ofType:@”plist”]; NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath]; NSLog(@”%@”, data);//直接打印数据。 }
打印出来的结果:
PlistDemo[6822:f803] { jack = { age = 22; “phone_num” = 13801111111; }; tom = { age = 36; “phone_num” = 13901111111; }; }

这样就把数据读取出来了。

4、创建和写入plist文件

在开发过程中,有时候需要把程序的一些配置保存下来,或者游戏数据等等。 这时候需要写入Plist数据。

写入的plist文件会生成在对应程序的沙盒目录里。

接着上面读取plist数据的代码,加入了写入数据的代码,

– (void)viewDidLoad { [super viewDidLoad]; //读取plist NSString *plistPath = [[NSBundle mainBundle] pathForResource:@”plistdemo” ofType:@”plist”]; NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath]; NSLog(@”%@”, data); //添加一项内容 [data setObject:@”add some content” forKey:@”c_key”]; //获取应用程序沙盒的Documents目录 NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES); NSString *plistPath1 = [paths objectAtIndex:0]; //得到完整的文件名 NSString *filename=[plistPath1 stringByAppendingPathComponent:@”test.plist”]; //输入写入 [data writeToFile:filename atomically:YES]; //那怎么证明我的数据写入了呢?读出来看看 NSMutableDictionary *data1 = [[NSMutableDictionary alloc] initWithContentsOfFile:filename]; NSLog(@”%@”, data1); // Do any additional setup after loading the view, typically from a nib. }
在获取到自己手工创建的plistdemo.plist数据后,在这些数据后面加了一项内容,证明输入写入了。

怎么证明添加的内容写入了呢?下面是打印结果:

%title插图%num%title插图%num

怎么学习iOS,如何学习iOS开发?

近年来ios app开发在不断发展中,各中小型也如雨后春笋纷纷露头,像广州商侣软件公司这样的app开发企业可以说是处处可见,然而ios app开发到底该如何入手,如何才能如鱼得水般在这个领域里面畅游呢?

一、什么是ios app开发
ios app开发是指针对苹果公司所生产的手机的ios系统的客户端软件进行开发,自从苹果手机开始上市以来,截止到2012年,4 年,65 万个 App,下载量 300 亿次,与开发者分成 50 亿美元,这是今年 WWDC苹果公布的数据。4 年来,苹果的 App Store 改变了很多人的命运,改变了人们的一些行为习惯。

在这里我还是要推荐下我自己建的iOS开发学习群:727474737,群里都是学ios开发的,如果你正在学习ios ,小编欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018*新的iOS进阶资料和高级开发教程

二、ios app开发前景如何
在这部分中国 iOS 开发者们看来,5 年来,苹果 App Store 带给我们*大的影响在于带来了巨大的机会和希望。而这种机遇更多的在于为个人、小团队开发者提供希望。在 App Store 面前,无论公司大小、也不管公司是否强大,一律都是平等的,这在以前是不存在这种平台的。因此对于小团队、个人开发者来说,它提供的是一种改变自身命运的平台机遇。只要能开发出足够好的产品,你就有机会在短时间内创造奇迹。

三、如何学习ios app开发

为了吸引、帮助更多的人成为苹果iOS app应用开发者,苹果上线了一个iOS app应用开发官方教程。想成为一名iOS应用开发者的朋友,不用再埋头苦啃什么秘籍了,苹果官方将会推出ios app开发教程来告诉你如何开发ios app应用,需要什么工具、哪方面的知识等等。现在苹果iOS设备用户数越来越多,开发者的收入也水涨船高,不少人都跃跃欲试但却又无从下手。现在有了苹果iOS应用开发官方教程,大家可以自我增值,说不定下一个畅销的iOS应用,就出自你的手。

开发ios app,除了需要必备的软件,比如Xcode、iOS SDK,还有硬件,比如一部Mac电脑、一部iOS设备用作测试。此外,你*好还是参加苹果的iOS开发者计划,这样,你才可以更好地测试你的app应用软件,甚至让你自己开发的app在iTunes App Store上架。

论想学什么,也无论出于什么目的想学,都需要你保持好奇心。但是作为刚想入门的新手,面对眼前海量的信息,或许根本不知道从哪里开始。想学习编程?想自学?想高效的搞定编程这件事儿?学习编程的网站给刚入门的你,赶紧学起来。

学习ios 。首先,基础很重要,学校开设的课程比如:数据结构和算法,设计模式,编译原理,操作系统原理,等不要认为是没有用的,在日后的编程中其实很多东西都需要用到那些知识。再掌握一门语言比如c/c++,因为很多底层的类库都是C写的。而且可以混编,特别是一些第三方的类库直接就是C++写的。其他的包括T-Sql,html,js等也可以了解下,因为基于hyper link方式的开发也在发展。

%title插图%num

然后,就要研究iOS开发的武器库了。入门的话可以看看基本的,很好理解也很实用。一定要学以致用!学以致用!学以致用!

1.Beginning.iOS.5.Development.Exploring.the.iOS.SDK.Dec.2011

%title插图%num

2.Learn_Objective-C_for_Java_Developers/ Objective-C编程之道

%title插图%num

3.iOS 10 Programming Cookbook

%title插图%num

这三本看下来可以试试做一些简单的小项目,但是这离大神的级别是远远不够的。可能你知道但是具体为什么这么用,或者更深层次的东西你不一定了解清楚,这个时候就要看进阶文档了。

针对程序员行业,这是一个需要努力奋斗的行业,也许他并不需要你有多高的文凭,好的文凭可以去大公司工作,没有好的文凭,但拥有丰富的工作经验,和开源库,也会是你本人实力的体现.所以,努力学习,路是自己走出来的,原地踏步谁也救不了你.。

 

iOS开发学习路线 +技巧整理

其实自学编程并不难,自学iOS移动开发也不是很难。

iOS拥有强大的开发工具IDE Xcode,Xcode是开发OS X 和 iOS 应用程序的*快捷的方式。Xcode 具有统一的用户界面设计,编码、测试、调试都在一个简单的窗口内完成。简单的界面构建器Interface Builder(简称IB)通过鼠标拖拽就可以快速构建APP UI,甚至完全不需要真机调试,拖什么样,真机就表现成什么样。

在这里我还是要推荐下我自己建的iOS开发学习群:727474737,群里都是学ios开发的,如果你正在学习ios ,小编欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018*新的iOS进阶资料和高级开发教程

分享一套完整的iOS学习路线图:

%title插图%num

清晰版大图 地址:https://github.com/shaojiankui/iOS-Route

OS开发技巧分享

1、pod Analyzing dependencies:

pod install —verbose —no-repo-update

pod update —verbose —no-repo-update

2、git SourceTree 超前某个版本,落后某个版本:

find . -name .DS_Store -print0 | xargs -0git rm -f —ignore-unmatchgit clean -d -fx “”git commit -am ‘Conflicts resolved’
3、git配置多个SSH:

http://www.jianshu.com/p/1fa5f8b21521

4、设置webview 请求头:

NSString *userAgent = [[[UIWebView alloc] init] stringByEvaluatingJavaScriptFromString:@”navigator.userAgent”];NSString *appName = @”app”;NSString *customUserAgent = [userAgent stringByAppendingFormat:@” %@/1.0″, appName];[[NSUserDefaults standardUserDefaults] registerDefaults:@{@”UserAgent”:customUserAgent}];
5、webview 获取title url:

NSString *title = [webView stringByEvaluatingJavaScriptFromString:@”document.title”];

NSString *url = [webview stringByEvaluatingJavaScriptFromString:@”document.location.href”];

6、字符串编码解码,解决iOS中的中文unicode编码问题:

https://github.com/zhangqihu/CDUrlDecode.git

7、webview js互调:

js执行OC代码:js是不能执行OC代码的,但是可以变相的执行,js可以将要执行的操作封装到网络请求里面,然后OC拦截这个请求,获取url里面的字符串解析即可,代理: – (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

OC调取写好的js代码:UIWebView方法 stringByEvaluatingJavaScriptFromString

8、设置状态栏为白色:

// Swiftoverride func preferredStatusBarStyle() -> UIStatusBarStyle { return UIStatusBarStyle.LightContent; }// OC- (UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent;}
9、iOS获取剪贴板的内容:

NSString *pasteUrl = [UIPasteboard generalPasteboard].string;

第七次全国人口普查公报解读

新时代高质量发展的人口机遇和挑战
——第七次全国人口普查公报解读 第七次全国人口普查是中国在站上“两个一百年”历史交汇点前夕所开展的一项重大国情国力调查。在党中央坚强领导下,第七次全国人口普查有效地经受住新冠肺炎疫情防控的严峻考验,平稳地完成了挨户采集逐人登记的系统工程,*终获取了详实的统计数据、形成了扎实的数据公报。这为我们进一步地完善人口发展战略、更长远地制定经济社会发展规划,从而切实地推动高质量发展,提供了不可多得的数据支撑。 相比以往历次全国人口普查,第七次全国人口普查顺应了新时代信息技术发展的大趋势、实现了一系列质量控制方法的新突破,从而做到了将人口基数查得更实、人口底数摸得更清。其一,第七次全国人口普查全面启用电子化的方式采集数据。700余万名普查人员持平板电脑或智能手机,深入数以亿计的家庭户及集体户,一举告别过去纸表手记这种效率相对不太高、质量可能受影响的数据采集方式。第七次全国人口普查同时还增设了普查对象联网自主填报通道,更好地满足了人们对于普查工作灵活性、隐秘性等方面的要求。电子化的方式确保数据可直接上报和实时核准,扎牢了普查的质量控制全过程中*关键的一道“篱笆”。其二,第七次全国人口普查充分利用部门行政记录校验数据。作为在证明公民有效身份、保障公民合法权益、便利公民社会活动等多方面具有特殊重要意义的信息,身份证号被首次列入普查的主要内容。这使得第七次全国人口普查可以同公安部门户籍登记、卫健部门妇幼统计等在内的大数据相挂钩,彼此间实现了各取所长、互通有无、查漏补缺,用大数据改善普查工作,推动数据质量控制技术更上一个“台阶”。依靠着推陈出新、多管齐下的质量控制举措,第七次全国人口普查总体上契合了求真求实、不重不漏的调查设计“初心”,漏登率仅为0.05%,属于国际上公认的低漏登水平,高质量普查为高质量发展提供有力的信息支持。特别是在全球首屈一指的人口大迁移大流动环境下,交出这样一份“答卷”更是殊为不易。 数量、结构、素质、分布是人口的基本范畴,第七次全国人口普查主要数据公报从这些方面出发,清晰地绘制出中国近10年间的人口发展“全景图谱”。 从人口数量看,近10年间,中国总人口数增长速度延续放缓势头。2020年,大陆地区人口总体规模达到14.1亿人,相较于2010年“六人普”时,增加7205万人,其年平均增长率为0.53%。这一增量比从2000年“五人普”到2010年“六人普”的10年间减少185万人,增速降低0.04个百分点。显然,中国人口高速甚至于超高速增长的时期已渐行渐远,人口惯性增长阶段正渐趋尾声,人口零增长乃至负增长的时代则渐行渐近。“十四五”时期预计将是21世纪*后一个人口完全正向增长的发展规划期,而到“十五五”时期,我们会迎来中国人口总量的“拐点”。人口增长势头放缓以至扭转,主要是出生人口数量下降的结果。党的十八大之后,生育政策调整完善步伐明显加大加快,面对着城镇化水平增长、受教育程度提高、离婚不婚率上升等诸多生育水平下行因素的持续影响,相当程度地推迟延缓了生育水平走低态势。但是因育龄妇女规模在减小、结构在老化等,出生人口数量降低的大走向不会根本改变,总人口数趋于零增长乃至负增长的基本面不会根本改变。迈入人口零增长乃至负增长时代,是中国在人口领域所面对的“百年未有之大变局”,是促进人口长期均衡发展进程需关注的先导性议题,深刻影响着高质量发展的劳动力供给量、消费者需求量等。 从人口结构看,近10年间,中国已跨过了*个快速人口老龄化期,我们很快还需应对一个更快速的人口老龄化期。2020年,大陆地区60岁及以上的老年人口总量为2.64亿人,已占到总人口的18.7%。自2000年步入老龄化社会以来的20年间,老年人口比例增长了8.4个百分点,其中,从2010年“六人普”到2020年第七次全国人口普查的10年间升高了5.4个百分点,后一个10年明显超过前一个10年,这主要与20世纪50年代*次出生高峰所形成的人口队列相继进入老年期紧密相关。而在“十四五”时期,20世纪60年代第二次出生高峰所形成的更大规模人口队列则会相继跨入老年期,使得中国的人口老龄化水平从*近几年短暂的相对缓速的演进状态扭转至增长的“快车道”,老年人口年净增量几乎是由21世纪的*低值(2021年出现)直接冲上*高值(2023年出现)。 积*应对人口老龄化的现实迫切性空前凸显,党的十九届五中全会应势而为地将其上升至国家战略的高度。未来直至21世纪中叶后,中国老年人口数量增长的步伐尽管时快时慢,但不会停,通过在劳动供给、财富储备、科技创新及产品服务供给等多方面持续发力,人口老龄化给高质量发展带来的压力有望得到化解,甚至于向动力转换。 从人口素质看,近10年间,中国人口教育水平又有新的较大幅度跨越,我们可在高等教育大众化时代中收获更多“人口质量红利”。2020年,大陆地区每10万人中具有大学文化程度的达到15467人,比2010年“六人普”时高出6537人,高中文化程度的相应比例同期也有升高,初中文化程度、小学文化程度比例以及不识字率则在降低。这无疑是新中国成立后,特别是改革开放后,教育事业持续发展所结出的“硕果”。义务教育推行、高中教育普及、特别是高等教育进入大众化阶段等一系列教育改革发展举措,未来还将推动中国人口教育水平不断迈向新的高度,从而以更加优质充裕的人才人力资源夯实创新驱动发展战略实施根基。高质量发展应当把劳动年龄人口数量减少、结构老化等方面的劣势寓于劳动年龄人口素质提高的优势中,从而释放新动力、激发新活力。 从人口分布看,近10年间,中国常住人口城镇化率在突破50%后仍保持快速增长趋势,我们还将延续大规模的乡城迁移流动。2020年,大陆地区常住人口城镇化率达63.9%,相较于2010年“六人普”时的49.7%,上升了14.2个百分点。人口迁移流动是城镇化率从2010年“六人普”到2020年第七次全国人口普查相继冲上50%和60%大关的主推进力,广东省也由此继续成为人口数量*大的省份。从发达国家城镇化的一般规律看,中国当前仍然处于城镇化率有潜力以较快速度提升的发展机遇期,“十四五”时期可突破65%的城镇化率,乡城之间因此还将呈现出大迁移大流动的基本格局。在以人为核心的新型城镇化战略推动下,历史上千百年的“乡土中国”正日益发展为“城镇中国”,这可成为实现高质量发展的重要力量“源泉”。 开发好、利用好第七次全国人口普查这一数据“宝藏”,将为新人口特征下有新思路、新人口形势下有新对策更好贡献力量。 (作者:中国人民大学人口与发展研究中心教授 翟振武) (原文链接:https://proapi.jingjiribao.cn/detail.html?id=339961)