FourV Zhang'Blog

开发随记,生活随笔,读书随感,旅游随心


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

  • 搜索

singleton是否可以这样写

发表于 2018-09-17 | 分类于 研发随笔 | 阅读次数
1
2
3
4
5
6
7
8
9
10
11
+ (instancetype)shareUser {
static JSBUserModel *_user;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_user = [NSKeyedUnarchiver unarchiveObjectWithFile:SavePath];
if (_user == nil) {
_user = [JSBUserModel new];
}
});
return _user;
}

在修改老项目的旧代码时,我和同事发现了这行几行代码!这是一个用户数据模型(userModel),用于存储用户的信息。

登录获取用户数据后,转换成模型,并归档到本地。当使用的时候到本地解档!解档!单例方法中解档?WHAT ?什么鬼?

疑惑:单例方法shareUser中的dispatch_once(&onceToken, ^{ xxxxxx}只执行一次,如何在使用的时候本地解档呢?我们对着代码改了又改,看了又看!

一个上午,当我们多次command + R重新运行项目都需要重新输入帐号密码的时候,顿时疑惑被解开:

单例指的是在程序运行期间存在与内存中的唯一的示例对象,当程序死掉或者被杀掉的时候,应用占用的内存会被销毁,内存中的单例自然也会被销毁掉!!
当再次启用应用的时候,会创建新的内存—新的单例实例!自然会走单例方法中`dispatch_once(&onceToken, ^{ xxxxxx}中的代码

NSLog打印失效

发表于 2018-09-13 | 分类于 研发随笔 | 阅读次数

平时项目中都是使用DEBUG控制开发和发布状态下输出打印功能,
突然有一天发现系统的NSLog打印失效了,挽救方法如下:
在xcode项目下使用组合键command + <打开编辑面板编辑面板.png

添加OS_ACTIVITY_MODE 关键字,勾选并修改value值为able,
重新运行即可!

记奇特的调试bug

发表于 2018-09-04 | 分类于 研发随笔 | 阅读次数

奇特的调试bug.png

传进来的model有值,并且可以打印model模型所有值;
但是打印model模型中的title、image、sort属性的时候,不是为nil,就是报错如下:
Execution was interrupted, reason: Attempted to dereference an invalid ObjC Object or send it an unrecognized selector. The process has been returned to the state before expression evaluation

原因排查:
打印的model为一个字典

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
id = ad3886be78de49c8a6f66dfe9ba715fa,
enable = 0,
album = 1,
delFlag = 1,
ifBuy = 0,
createDate = 1505893668000,
vtime = ,
type = 0,
title = 微课堂,
price = 1,
image = 65617e87de1c4084ba1b78a673363b99,
updateDate = 1508724726000,
sort = 1
}

正确的打印出来如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
(lldb) po model.yy_modelDescription
< videosModel: 0x600002a75700> {
enable = "0";
ifBuy = 0;
image = "b31e4d4ac6fd472babe9bae7c768bc0d";
price = 2;
title = "政策解读1";
type = "1";
videoId = "4bb5310dcb9d4e7cb20aa00796da921f"
}
(lldb) po model
< videosModel: 0x600002a75700>

排查得出结果:网络请求回来的json类型数据没有转换为模型类型!!!

查看模型中的声明和实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.h
@interface videosModel : NSObject
@property (nonatomic, copy) NSString *videoId;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *enable;
@property (nonatomic, copy) NSString *image;
@property (nonatomic, assign) NSInteger ifBuy;
@property (nonatomic, strong) NSNumber *price;
@end
@interface videosListModel : NSObject
@property (nonatomic, strong) NSArray < videosModel *> *videos;
@end
.m
@implementation videosModel
+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper {
return @{@"videoId":@"id"};
}
@end
@implementation videosListModel
@end

在.m文件中缺少了YYModel的类方法(自定义容器类属性映射模型类的方法)

1
2
3
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"videos" : [videosModel class]};
}

包裹BOOL值NSNumber对象和等价的三目运算区别何在

发表于 2018-09-03 | 分类于 研发随笔 | 阅读次数

后台人员提供了一个网络请求接口,接口文档如下:
接口文档.png
使用字典将参数传递过来给后台,移动端提供的参数isAttention是BOOL类型,要转换成后台所需要的int类型;
因为字典之中键值只能是对象类型,以往都是将int类型包装成NSNumber类型放在字典里进行传递,请求准确无误。

1
2
3
方式一 : {@"isAttention":@(isAttention)}
方式二 : [NSNumber numberWithBool:attention]
方式三 : attention ? @1 : @0

不巧的是,今天使用上述两种方式都报错–400.

Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set., NSUnderlyingError=0x604000c51100 {Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: bad request (400)" UserInfo={NSLocalizedDescription=Request failed: bad request (400), NSErrorFailingURLKey=http://test.******.com/jsb_webserver/attention/user, com.alamofire.serialization.response.error.data = <........>, com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x60400082f140> { URL: http://test.******.com/jsb_webserver/attention/user } { Status Code: 400, Headers { Connection = [ close ], Content-Language = [ en ], Content-Type = [ text/html;charset=utf-8 ], Content-Length = [ 1003 ], Date = [ Mon, 03 Sep 2018 06:34:01 GMT ] } }}}}
最终使用第三种方式包装BOOL类型参数,请求成功的!!!
但是本人还是有些不解,前两种写法和第三种有什么本质上的区别,
求大神不吝赐教!!!

导航栏状态栏通透ios11适配

发表于 2018-08-22 | 分类于 研发随笔 | 阅读次数

状态栏通透.png
想要实现状态栏通透的效果:
iOS10及以下设备设置控制器

1
2
3
4
5
6
7
8
- (void)viewDidLoad {
[super viewDidLoad];
// 设置导航栏的背景图透明
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
// 设置导航栏底部线不显示
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
self.automaticallyAdjustsScrollViewInsets = NO; // 9.0设备上
}

在ios11的设备上,可以设置UIScrollView的contentInsetAdjustmentBehavior的属性;

例如:设置tableView的contentInsetAdjustmentBehavior的属性

1
2
3
4
5
if (@available(iOS 11.0, *)) {
_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
}

查看这个属性的相关信息得知,将要废除,并有新的属性替换

1
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES

因为控制器的automaticallyAdjustsScrollViewInsets默认是YES,也就是控制器的视图会自动适应导航栏和状态栏的缩进;反之不自动适应,则从屏幕顶部开始。

UIScrollViewContentInsetAdjustmentBehavior同理,设置UIScrollViewContentInsetAdjustmentNever则不自动适应,从屏幕顶部开始。

1
2
3
4
5
6
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {`
UIScrollViewContentInsetAdjustmentAutomatic, // Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller, regardless of whether the scroll view is scrollable
UIScrollViewContentInsetAdjustmentScrollableAxes, // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)
UIScrollViewContentInsetAdjustmentNever, // contentInset is not adjusted
UIScrollViewContentInsetAdjustmentAlways, // contentInset is always adjusted by the scroll view's safeAreaInsets
`} API_AVAILABLE(ios(11.0),tvos(11.0));

导航栏通透.gif

APP上架被拒日常(6)-IPv6 网络错误

发表于 2018-06-07 | 分类于 发布上架 | 阅读次数

原文

We discovered one or more bugs in your app when reviewed on iPhone running iOS 11.1 on Wi-Fi connected to an IPv6 network.
Specifically, your app still displays a network error message and we are unable to log in.
Please see attached screenshots for details.
Next Steps
To resolve this issue, please run your app on a device to identify any issues, then revise and resubmit your app for review.
If we misunderstood the intended behavior of your app, please reply to this message in Resolution Center to provide information on how these features were intended to work.
For new apps, uninstall all previous versions of your app from a device, then install and follow the steps to reproduce the issue. For updates, install the new version as an update to the previous version, then follow the steps to reproduce the issue.
Resources
For information about testing your app and preparing it for review, please see Technical Note TN2431: App Testing Guide.
For a networking overview, please review About Networking. For a more specific overview of App Review’s IPv6 requirements, please review the IPv6 and App Review discussion on the Apple Developer Forum.

译文:

当在连接到IPv6网络的Wi-Fi上运行ios11.1时,我们在应用程序中发现了一个或多个错误。
具体来说,您的应用程序仍然显示一个网络错误信息,我们无法登录。
详情请见附件截图。
下一个步骤
要解决这个问题,请在设备上运行您的应用程序来识别任何问题,然后修改并重新提交您的应用程序以供审查。
如果我们误解了您的应用程序的意图行为,请在Resolution Center中回复此消息,以提供这些特性如何工作的信息。
对于新的应用程序,从设备上卸载之前所有的应用程序,然后安装并执行复制问题的步骤。对于更新,将新版本作为以前版本的更新安装,然后按照以下步骤重新生成问题。
资源
有关测试您的应用程序并准备进行审查的信息,请参阅技术说明TN2431:应用程序测试指南。
要了解网络概况,请回顾网络。关于应用程序审查的IPv6需求的更具体的概述,请回顾一下关于苹果开发者论坛的IPv6和应用程序审查讨论。

解决方案

针对被拒内容中提到了IPv6 网络环境下,网络错误导致无法登录!

  • 首先保证登录接口/截图中展示页面内网络接口能够正常使用,以防止在苹果审核期间宕机无法使用弹出网络错误的提示框;
  • 其次搭建IPv6 的网络环境,并且录制使用APP的视频,上传到youtube上,并获取该视频的播放地址.
  • 在重新打包提交的备注信息里或者问题中心的回复框里,附带上述视频地址以及相关解释说辞,提交审核即可.

附上截图:
photo.png

APP上架被拒日常(5)-Payments - In-App Purchase

发表于 2018-06-07 | 分类于 发布上架 | 阅读次数

被拒(一)原文

Hello,Thank you for providing the information. After further review, we found the following rejection:
We noticed that your app or its metadata enables the purchase of content, services, or functionality in the app by means other than the in-app purchase API, which is not appropriate for the App Store.
The next submission of this app may require a longer review time.
Next Steps

  • Review the In-App Purchase section of the App Store Review Guidelines.
  • Ensure your app is compliant with all sections of the App Store Review Guidelines and the Terms & Conditions of the Apple Developer Program.
  • Once your app is fully compliant, resubmit your app for review.
    Submitting apps designed to mislead or harm customers or evade the review process may result in the termination of your Apple Developer Program account. Review the Terms & Conditions of the Apple Developer Program to learn more about our policies regarding termination.
    If you believe your app is compliant with the App Store Review Guidelines, you may submit an appeal. Alternatively, you may provide additional details about your app by replying directly to this message.

译文:

您好,谢谢您提供的信息。经过进一步的审查,我们发现了以下的拒绝:
我们注意到,你的app或它的元数据可以通过APP内购买API以外的方式购买APP中的内容、服务或功能,这并不适合APP Store。
这款应用的下一个提交可能需要更长的审查时间。
下一个步骤
-检查App Store内购买部分评审指南。
-确保您的应用程序符合app Store评审指南的所有章节以及苹果开发者计划的条款和条件。
-一旦你的应用完全兼容,重新提交你的应用进行审查。
提交旨在误导、伤害客户或逃避审查过程的应用程序,可能会导致您的Apple Developer程序帐户被终止。查看Apple Developer Program的条款和条件,了解更多关于终止的政策。
如果你认为你的应用程序符合app Store评审准则,你可以提出上诉。或者,您可以通过直接回复此消息来提供关于您的应用程序的其他详细信息。

解决方案

一. 审核期间显示会员卡,让苹果审核员使用内购买的方式 购买会员,而不是使用内购以外的 方式购买,在此基础上还有以下两种处理方式选择
1)被拒内容中已经发出警告:逃避审核规则,可能导致开发者帐号封禁;根据提示此次把第三方支付模块注释掉提交上线,审核通过后,再次打开第三方支付模块,以修复bug的名义上线
面临问题: 导致首个版本短时间内无法使用第三方支付(微信,支付宝等)

2)保留第三方支付模块,添加一个实体商品(类似淘宝),使用微信支付方式;需要设计一个新的UI商品界面
问题:时间成本比较高,业务逻辑繁琐

推荐方案1),我们是使用方案1)解决的问题.

二. 审核期间隐藏会员卡信息,审核通过后显示会员卡信息,并且不需要添加内购支付的逻辑,保留第三方支付模块代码.

面临问题:苹果审核可能会检测到第三方支付的相关库,譬如微信的sdk,支付宝的sdk.导致开发者帐号封禁

附上截图:
图.png

被拒(二)原文

We noticed that your app is using consumable in-app purchase products as intermediary currency for the exchange of items that function as non-renewing subscriptions.
Next Steps
To resolve this issue, please delete your consumable in-app purchase products, then create separate non-renewing subscription in-app purchase products for each item that the user would have exchanged those consumable products for. This product type matches the usage model for the products you are ultimately selling to your users.
Note: The product type cannot be changed once an in-app purchase product has been created. Therefore, you will need to create a new in-app purchase product with the correct product type.
To create new in-app purchases:

  • Log in to iTunes Connect
  • Click on “My Apps”
  • Select your app
  • Click on “Features” to create new in-app purchases
  • Click Save
  • Once you’ve completed all changes, click the “Submit for Review” button at the top of the App Version Information page.
    Resources
    More information on in-app purchase product types is available in the In-App Purchase Programming Guide.

译文:

我们注意到,您的应用程序正在使用可消费的内购产品作为交换项目的中介货币,这些项目的功能是不可更新的订阅。
下一个步骤
为了解决这个问题,请删除您的可消费应用内购买产品,然后为用户将这些可消费产品交换的每个项目创建单独的不可更新的应用内购买产品。该产品类型与您最终销售给用户的产品的使用模型相匹配。
注意:在创建内购产品之后,不能更改产品类型。因此,您需要创建一个具有正确产品类型的应用程序内购买产品。
创建新的应用内购买:
-登录iTunes Connect。
-点击“我的应用”
—选择你的应用
-点击“功能”来创建新的内购。
—点击保存
-完成所有更改后,点击App版本信息页面顶部的“提交审核”按钮。

解决方案

根据提示解决就可以,删除掉appstore类型不正确(消费类型)的内购产品,然后重新创建正确类型(非续期订阅)的内购产品即可.

图1.png
图2.png

APP上架被拒日常(4)- 私有API - Software Requirements

发表于 2018-06-07 | 分类于 发布上架 | 阅读次数

原文:

Your app uses the “prefs:root=” non-public URL scheme, which is a private entity. The use of non-public APIs is not permitted on the App Store because it can lead to a poor user experience should these APIs change
Continuing to use or conceal non-public APIs in future submissions of this app may result in the termination of your Apple Developer account, as well as removal of all associated apps from the App Store
Next Steps
To resolve this issue, please revise your app to provide the associated functionality using public APIs or remove the functionality using the “prefs:root” or “App-Prefs:root” URL scheme.
If there are no alternatives for providing the functionality your app requires, you can file an enhancement request.

译文:

您的应用程序使用“prefs:root=”非公开URL组合,这是一个私有API。应用商店不允许使用非公有api,因为如果这些api发生变化,会导致糟糕的用户体验
继续使用或隐藏私有API,在以后提交这个应用程序时,可能会导致你的苹果开发者账户被终止,并从应用商店中删除所有相关的应用
下一个步骤
要解决这个问题,请修改应用程序,使用公共api提供相关功能,或者删除使用“prefs:root”或“app - prefs:root”私有API相关功能。
如果没有提供应用程序所需功能的替代方案,您可以提交增强请求。

解决方案:

1)全局搜索项目中”prefs:root”关键词字眼,并将搜索到的结果分情况删除或者注释掉或者寻找替代方法;此外如果不放心私有API问题,可以查找项目中是否存在其他私有API,如有删除掉即可.
此方法推荐!!!
2)如果通过方法1)解决了私有API的问题,但是应用内相关功能却无法实现了,就给苹果提交请求,增加新的公有API!不过此方法漫长不一定能解决问题

APP上架被拒日常(3)- 误判为企业应用

发表于 2018-06-07 | 分类于 发布上架 | 阅读次数

原文:

We found that your app is an in-house app, intended for employees or members of your organization. As such, it is not appropriate for the App Store.
For information on distributing proprietary, in-house apps, please refer to the Apple Developer Enterprise Program.

译文:

我们发现您的APP是一个公司内部APP,用于员工或您的组织成员。因此,它并不适合应用程序商店。
有关分配专有的信息,企业内部应用程序,请参阅苹果开发者计划

解决方案:

上一次APP被拒,回复的相关内容有些片面,导致苹果审核员认为应用是一个企业应用,不适合上架到应用商店,只需要解释清楚APP是提供给哪些人群使用,不仅仅是针对公司员工,还有除员工以外的大众用户群体,则可以解决此问题

APP上架被拒日常(2)- Data Collection and Storage

发表于 2018-06-07 | 分类于 发布上架 | 阅读次数

原文:

Guideline 5.1.1 - Legal - Privacy - Data Collection and StorageWe noticed that your app requires users to register with personal information to access non account-based features. Apps cannot require user registration prior to allowing access to app content and features that are not associated specifically to the user.Please see attached screenshots for details
Next Steps
User registration that requires the sharing of personal information must be optional or tied to account-specific functionality. Additionally, the requested information must be relevant to the features.
Request a phone call from App Review
At your request, we can arrange for an Apple Representative to call you within the next three to five business days to discuss your App Review issue

译文:

准则5.1.1 -法律-隐私保护-数据收集和存储
我们注意到你的应用程序需要用户通过提交个人信息注册帐号来访问一些不基于帐户之上的功能特性。应用程序不能在允许访问与用户没有特定关联的应用程序内容和特性之前要求用户注册。详情请见附件截图
接着下一步
需要共享个人信息的用户注册必须是可选的,或者绑定到特定于帐户的功能。此外,所请求的信息必须与特性相关。
请求App Review的电话
根据您的要求,我们可以安排一位苹果代表在接下来的3到5个工作日内给您打电话,讨论您的应用程序审核问题。

复现步骤:

游客状态,点击观看”被拒截图1”中的视频,因为涉及到视频用户授权需要用户信息,所以会弹登录注册页面

解决方案:

1)在游客状态下,隐藏这些需要用户信息的相关内容,此方法比较推荐!!!
2)如果隐藏实现比较繁琐的话,可以在苹果审核期间,程序内部默认一个用户cookie,从而使得游客状态访问相关信息不需要用户登录;审核通过后,使用真实帐号的cookie. 这个方法实现过程中需要注意不能改动现有其他功能的逻辑以及审核状态之间的转换,比较繁琐麻烦
3)请求与app review电话联系,等待在未来3–5工作日内与审核人员电话沟通解释—-游客状态下,访问相关内容为何需要登录注册.如果不登录注册会出现什么问题.磨破嘴皮子说服审核员,考验沟通技术,看运气

附上截图:
被拒截图1.jpeg
被拒截图2.jpg

12…4
FourV Zhang

FourV Zhang

记录生活的点点滴滴,待岁月逝去,回首往事,嘴角扬起久违的笑容

32 日志
4 分类
5 标签
© 2018 FourV Zhang
由 Hexo 强力驱动
主题 - NexT.Pisces