IOS知识点-小技巧-小笔记(2)

xcode中,全局去掉项目warning的开头在Builder Setttings->Inhibit All Warnings(抵制所有的警告).当把它设置为Yes时,编译项目就不会出现warning警告了.
因为部分引入的第三方的项目 去掉警告


清理icon 角标 对于ios11 没有去测试

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
/**
刷新本地和服务器的图标 (不在appIcon上显示推送数量,但是在系统通知栏保留推送通知的方法)
@param noti <#noti description#>
*/
- (void)refreshPushBageValue:(NSNotification *)noti{
NSNumber *value = [noti object];
//
if(kiOS11Later){
/*
iOS 11后,直接设置badgeNumber = -1就生效了
*/
[UIApplication sharedApplication].applicationIconBadgeNumber = value.integerValue;
[JPUSHService setBadge:value.integerValue];
}else{
// 原理是 发送了一个本地推送 无消息的, 如果本地推送有处理 需要处理下
UILocalNotification *clearEpisodeNotification = [[UILocalNotification alloc] init];
clearEpisodeNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:(0.3)];
clearEpisodeNotification.timeZone = [NSTimeZone defaultTimeZone];
/// 根据这个消息 不处理本地
clearEpisodeNotification.alertTitle = @"清理icon";
clearEpisodeNotification.applicationIconBadgeNumber = value.integerValue;
[[UIApplication sharedApplication] scheduleLocalNotification:clearEpisodeNotification];
}
}

终端代理(临时方案)

1
2
3
在终端中执行以下代码, 1 为http 代理, 2 为全部代理 . ;电脑开启代理软件
export http_proxy=http://127.0.0.1:1087 当前临时方案, 关闭后就不走代理了
export all_proxy=socks5://127.0.0.1:1086 这个是临时 都走代理 不光http ,会很快

通过宏定义判断是否引入的是framework,反之则使用双引号,实用!

1
2
3
4
5
6
7
8
9
10
#if __has_include(<xxx/xxx.h>)
#import <xxx/xxx.h>
#else
#import "xxx.h"
#endif
#if __has_include(<GPUImage/GPUImageFramework.h>)
#import <GPUImage/GPUImageFramework.h>
#else
#import "GPUImage.h"

swift 打印内存地址

Unmanaged.passRetained(self as AnyObject)//这个引用计数会+1
Unmanaged.passUnretained(self as AnyObject) // 这个引用计数+0

如下输出 Unmanaged(_value: )


部分服务端更改, 验证了cookie app 中没有cookie 清除 造成服务端返回400 和413, 然后加入cookie 清理

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
URLCache.shared.removeAllCachedResponses()
let cookies = HTTPCookieStorage.shared.cookies
if cookies != nil && cookies!.count>0{
for cookie in cookies!{
HTTPCookieStorage.shared.deleteCookie(cookie)
}
}
//iOS9.0以上使用的方法
if #available(iOS 9.0, *) {
let dataStore = WKWebsiteDataStore.default()
dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), completionHandler: { (records) in
for record in records{
//清除本站的cookie
if record.displayName.contains("sina.com"){//这个判断注释掉的话是清理所有的cookie
WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {
//清除成功
print("清除成功\(record)")
})
}
}
})
} else {
//ios8.0以上使用的方法
let libraryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
let cookiesPath = libraryPath! + "/Cookies"
try!FileManager.default.removeItem(atPath: cookiesPath)
}

1 宏
1.1 has_include
用于判断是否包含某些头文件 例如:
`#if
has_include()`

1.2 NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END
两者搭配使用,在这两个宏之间的所有函数变量都是不可空。如果在这两个宏之间,想要可空的函数变量,需要单独设置 nullable关键字。

1.3 UNAVAILABLE_ATTRIBUTE
不可用。在方法或者属性 加上这个宏之后。将变成不可用。

1.4 UI_APPEARANCE_SELECTOR
加到属性后面,所有该属性的实例都统一设置。


IPv6 问题:
1 使用域名
2 手动转换
假设访问http://67.218.154.33
转换为ipv6 形式 : http://[::ffff:67.218.154.33]

注 找了一个解释:https://www.jianshu.com/p/1312e98cd35b

—- 获取类名—
oc

1
2
3
4
/// switf 代码会带程序名
NSString *selfClassName = NSStringFromClass([self class]);
/// 去除程序名
selfClassName = [selfClassName componentsSeparatedByString:@"."].lastObject;

swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 返回内部类名
print("class: \(object_getClassName(self))")
// 返回应用程序名+类名
print("class: \(NSStringFromClass(self.dynamicType))")
// 返回应用程序名+类名,并去掉应用程序名
print("class: \(NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!)")
// 返回应用程序名+类名+内存地址
print("class: \(self)")
// 返回应用程序名+类名+内存地址
print("class: \(self.description)")
// 返回类名
print("class: \(self.dynamicType)")

Swizzle touchesBegan:withEvent:事故

得实现override touches 方法原因见
地址


ios 设备目录获取

1
2
3
4
5
6
7
8
9
10
// 获取沙盒主目录路径
NSString *homeDir = NSHomeDirectory();
// 获取Documents目录路径
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
// 获取Library的目录路径
NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
// 获取Caches目录路径
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
// 获取tmp目录路径
NSString *tmpDir = NSTemporaryDirectory();

程序目录

1
2
3
NSLog(@"%@",[[NSBundle mainBundle] bundlePath]);
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"apple" ofType:@"png"];
UIImage *appleImage = [[UIImage alloc] initWithContentsOfFile:imagePath];

libstdc++适配Xcode10与iOS12

原因是苹果在XCode10和iOS12中移除了libstdc++这个库,由libc++这个库取而代之,苹果的解释是libstdc++已经标记为废弃有5年了,建议大家使用经过了llvm优化过并且全面支持C++11的libc++库。

beta 版本的xcode 10 拷贝下xcode9 的文件(注 模拟器 还是崩溃)

1
2
3
cp /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/libstdc++.* /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/
cp /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/libstdc++.* /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/

根本解决办法:

如果你自己的业务模块使用了libstdc++,那么就把模块代码重新调整为依赖libc++,然后重新检查是否存在问题,重新编译
如果你引用的三方库使用了libstdc++,那么向三方库寻求支持,进行升级


查看应用初始化时间
在Xcode中,可以通过设置环境变量来查看App的启动时间,DYLD_PRINT_STATISTICS和DYLD_PRINT_STATISTICS_DETAILS。(这个是更详细的)
如图设置:控制台会输出时间

一个App在执行main函数前包括app delegate的系列方法如applicationWillFinishLaunching时,会做许多系统级别的准备.而在iOS10之前,开发者很难清楚自己App为何启动加载慢.而通过在工程的scheme中添加环境变量DYLD_PRINT_STATISTICS,设置Value为1,App启动加载时就会有启动过程的日志输出. 现在(iOS 10之后)Apple对DYLD_PRINT_STATISTICS的日志输出结果进行了简化,使得更容易让开发者理解.


iOS开发之使用P3图片导致崩溃的解决方法

最近app刚上架,突然收到大面积投诉….一看bugly,9.0-9.3的机器无一幸免,由于项目里有些图标是我直接从阿里图库下载的,问了UI P3,16进制的图片是什么他也说不清,索性让他重新做图了,这个问题只要图片是UI做图基本就可避免

1.打包成ipa

2.把ipa的后缀改成zip,解压缩(这时候会看到一个Payload文件夹)

3.打开终端 输入 cd

4.把 Payload 拖动到终端里(这里的拖动只是为了获取这个文件在电脑上的地址), 回车

5.在终端输入 find . -name ‘Assets.car’ 回车(会输出找到的位置)

6.在终端输入 sudo xcrun –sdk iphoneos assetutil –info ./Assets.car > /tmp/Assets.json 回车
(car 地址可以根据上面找到的位置填入)

7.在终端输入 open /tmp/Assets.json 回车

8.这时候会打开一个text 搜索 DisplayGamut 看看后面是不是P3 如果搜索到的是p3 图片格式还是不对,如果是空或者搜索到显示的不是P3,那图片就对了,根据Name去查找项目里的这张图片吧,然后将其替换.

转自点击


UIView 设置单边圆角

1
2
3
4
5
6
7
8
9
10
11
/// 设置单边圆角
private func setMaskLayer(){
let corner = self.height/2
let maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [UIRectCorner.bottomLeft,UIRectCorner.topLeft], cornerRadii: CGSize.init(width: corner, height: corner));
let maskLayer = CAShapeLayer.init()
maskLayer.frame = self.bounds
maskLayer.path = maskPath.cgPath
self.layer.mask = maskLayer;
}

jsonp 转json 正则

str.match(“.?({.}).*”)返回数组第一个


记录一个逗号分隔用法

1
2
3
4
5
6
7
// 多值的设置,使用逗号分隔
// 注意:if let语句中不能使用&& || 条件
// if let中只要有任何一个条件为nil,就跳出循环
if let name = oName, age = oAge {
print("Hi~" + name + "年龄:" + String(age))
}

IOS脚本打包 IPA(.APP转.IPA)

将要转化的.app文件放到 convertToIpa.sh 同目录之中

运行 convertToIpa.sh 脚本

打开 Terminal,cd 到 convertToIpa.sh 的目录,执行

./convertToIpa.sh appName(.app 的名字)

如果提示 permission denied,则用 chmod 777 distribute.sh 命令赋予权限后,再执行一次。

等脚本之行结束后,会在当前文件夹下生成 appName 文件夹,里面的 appName.ipa 就是我们最终想要的包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
mkdir $1
mkdir $1/Payload
cp -r $1.app $1/Payload/$1.app
cp Icon.png $1/iTunesArtwork
cd $1
zip -r $1.ipa Payload iTunesArtwork
exit 0

xcode 编译线程数

1.获取当前内核数:
$ sysctl -n hw.ncpu
2.设置编译线程数:
$ defaults write com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks 8
3.获取编译线程数:
$ defaults read com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks
4.显示编译时长:

$ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

iOS12.1 使用 UINavigationController + UITabBarController( UITabBar 磨砂),设置hidesBottomBarWhenPushed后,在 pop 后,会引起TabBar布局异常

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// .h
@interface CYLTabBar : UITabBar
@end
// .m
#import "CYLTabBar.h"
/**
* 用 block 重写某个 class 的指定方法
* @param targetClass 要重写的 class
* @param targetSelector 要重写的 class 里的实例方法,注意如果该方法不存在于 targetClass 里,则什么都不做
* @param implementationBlock 该 block 必须返回一个 block,返回的 block 将被当成 targetSelector 的新实现,所以要在内部自己处理对 super 的调用,以及对当前调用方法的 self 的 class 的保护判断(因为如果 targetClass 的 targetSelector 是继承自父类的,targetClass 内部并没有重写这个方法,则我们这个函数最终重写的其实是父类的 targetSelector,所以会产生预期之外的 class 的影响,例如 targetClass 传进来 UIButton.class,则最终可能会影响到 UIView.class),implementationBlock 的参数里第一个为你要修改的 class,也即等同于 targetClass,第二个参数为你要修改的 selector,也即等同于 targetSelector,第三个参数是 targetSelector 原本的实现,由于 IMP 可以直接当成 C 函数调用,所以可利用它来实现“调用 super”的效果,但由于 targetSelector 的参数个数、参数类型、返回值类型,都会影响 IMP 的调用写法,所以这个调用只能由业务自己写。
*/
CG_INLINE BOOL
OverrideImplementation(Class targetClass, SEL targetSelector, id (^implementationBlock)(Class originClass, SEL originCMD, IMP originIMP)) {
Method originMethod = class_getInstanceMethod(targetClass, targetSelector);
if (!originMethod) {
return NO;
}
IMP originIMP = method_getImplementation(originMethod);
method_setImplementation(originMethod, imp_implementationWithBlock(implementationBlock(targetClass, targetSelector, originIMP)));
return YES;
}
@implementation CYLTabBar
+ (void)load {
/* 这个问题是 iOS 12.1 Beta 2 的问题,只要 UITabBar 是磨砂的,并且 push viewController 时 hidesBottomBarWhenPushed = YES 则手势返回的时候就会触发。
出现这个现象的直接原因是 tabBar 内的按钮 UITabBarButton 被设置了错误的 frame,frame.size 变为 (0, 0) 导致的。如果12.1正式版Apple修复了这个bug可以移除调这段代码(来源于QMUIKit的处理方式)*/
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (@available(iOS 12.1, *)) {
OverrideImplementation(NSClassFromString(@"UITabBarButton"), @selector(setFrame:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP originIMP) {
return ^(UIView *selfObject, CGRect firstArgv) {
if ([selfObject isKindOfClass:originClass]) {
// 如果发现即将要设置一个 size 为空的 frame,则屏蔽掉本次设置
if (!CGRectIsEmpty(selfObject.frame) && CGRectIsEmpty(firstArgv)) {
return;
}
}
// call super
void (*originSelectorIMP)(id, SEL, CGRect);
originSelectorIMP = (void (*)(id, SEL, CGRect))originIMP;
originSelectorIMP(selfObject, originCMD, firstArgv);
};
});
}
});
}
@end

来源 https://github.com/ChenYilong/iOS12AdaptationTips/issues/3


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pod 'AFNetworking' //不显式指定依赖库版本,表示每次都获取最新版本
pod 'AFNetworking', '~>0' //高于0的版本,写这个限制和什么都不写是一个效果,都表示使用最新版本
pod 'AFNetworking', '~> 0.1.2' //使用大于等于0.1.2但小于0.2的版本
pod 'AFNetworking', '~>0.1' //使用大于等于0.1但小于1.0的版本
pod 'AFNetworking', '2.0' //只使用2.0版本
pod 'AFNetworking', '= 2.0' //只使用2.0版本
pod 'AFNetworking', '> 2.0' //使用高于2.0的版本
pod 'AFNetworking', '>= 2.0' //使用大于或等于2.0的版本
pod 'AFNetworking', '< 2.0' //使用小于2.0的版本
pod 'AFNetworking', '<= 2.0' //使用小于或等于2.0的版本
pod 'AFNetworking', :git => 'http://gitlab.xxxx.com/AFNetworking.git', :branch => 'R20161010' //指定分支
pod 'AFNetworking', :path => '../AFNetworking' //指定本地库


1
2
3
4
// //排序
// NSSortDescriptor *isDefault = [NSSortDescriptor sortDescriptorWithKey:@"isDefault" ascending:NO];
// NSSortDescriptor *isUse = [NSSortDescriptor sortDescriptorWithKey:@"isOnlyUse" ascending:NO];
// [self.dataArray sortUsingDescriptors:@[isDefault,isUse]];

系统装 carthage 造成的终端编译ipa找不到编辑器

1
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/

——node link— 失败问题

Could not symlink share/doc/node/gdbinit
Target /usr/local/share/doc/node/gdbinit
already exists. You may want to remove it:
rm ‘/usr/local/share/doc/node/gdbinit’

解决
1 sudo chown -R $USER /usr/local
2 brew link –overwrite node


xcode 打包多taget 版本号自动同步
添加 Shell 脚本; 在Xcode Build Phases -> 添加 Run Script;
注: 会影响打包, 直接自动打包shell 脚步直接处理, 方法同样

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
# Type a script or drag a script file from your workspace to insert its path.
if [ $CONFIGURATION == Release ]; then
echo "Bumping build number..."
plist=${INFOPLIST_FILE}
buildnum=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${plist}")
if [[ "${buildnum}" == "" ]]; then
echo "No build number in $plist"
exit 2
fi
echo "Bumped build number to $buildnum"
buildnum=$(expr $buildnum + 1)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildnum" "${INFOPLIST_FILE}"
echo "Update build number to Current Project Version"
agvtool new-version -all $buildnum
echo "Keep Extension Target build version and number as same as app"
buildver=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plist}")
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildver" "$SRCROOT/$ZBiOSNotificationService/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildver" "$SRCROOT/$ZBiOSNotificationService/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildnum" "$SRCROOT/$ZBiOSNotificationService/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildnum" "$SRCROOT/$ZBiOSNotificationService/Info.plist"
else
echo $CONFIGURATION "build - Not bumping build number."
fi

时间的一个处理

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
// 获取代表公历的NSCalendar对象
let gregorian = Calendar(
identifier: .gregorian)
// 获取当前日期
let dt = Date()
// 定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
// let unitFlags: NSCalendar.Unit = [.year, .month, .day, .hour, .minute, .second, .weekday]
// 获取不同时间字段的信息
let comp = gregorian.dateComponents(
[.year, .month, .day, .hour, .minute, .second, .weekday],
from: dt)
// 获取各时间字段的数值
// 再次创建一个NSDateComponents对象
var comp2 = DateComponents()
// 设置各时间字段的数值
comp2.year = comp.year
comp2.month = comp.month
comp2.day = comp.day
comp2.hour = comp.hour
comp2.minute = 34
// 通过NSDateComponents所包含的时间字段的数值来恢复NSDate对象
let date = gregorian.date(from: comp2)
if let date = date {
print("获取的日期为:\(date)")
}
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
32
33
// 获取代表公历的NSCalendar对象
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
// 获取当前日期
NSDate* dt = [NSDate date];
// 定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
unsigned unitFlags = NSCalendarUnitYear |
NSCalendarUnitMonth | NSCalendarUnitDay |
NSCalendarUnitHour | NSCalendarUnitMinute |
NSCalendarUnitSecond | NSCalendarUnitWeekday;
// 获取不同时间字段的信息
NSDateComponents* comp = [gregorian components: unitFlags
fromDate:dt];
// 获取各时间字段的数值
NSLog(@"现在是%ld年" , comp.year);
NSLog(@"现在是%ld月 " , comp.month);
NSLog(@"现在是%ld日" , comp.day);
NSLog(@"现在是%ld时" , comp.hour);
NSLog(@"现在是%ld分" , comp.minute);
NSLog(@"现在是%ld秒" , comp.second);
NSLog(@"现在是星期%ld" , comp.weekday);
// 再次创建一个NSDateComponents对象
NSDateComponents* comp2 = [[NSDateComponents alloc]
init];
// 设置各时间字段的数值
comp2.year = 2013;
comp2.month = 4;
comp2.day = 5;
comp2.hour = 18;
comp2.minute = 34;
// 通过NSDateComponents所包含的时间字段的数值来恢复NSDate对象
NSDate *date = [gregorian dateFromComponents:comp2];
NSLog(@"获取的日期为:%@" , date);


pod 组件,使用时, 头文件报 重复导入,使用检查头文件的方式导入

1
2
3
4
5
#if __has_include(<ShareSDK/ShareSDK.h>)
#import <ShareSDK/ShareSDK.h>
#else
#endif

格式化数据

1
2
3
4
5
6
7
8
NSLog(@"%02ld",2);
NSLog(@"%0.2f",0.2656);
NSLog(@"%0.2f",0.2646);
注意的是%0.2f 是会对数字进行一个四舍五入
14:57:28.506 App[4010:98217] 02
2016-06-20 14:57:28.507 App[4010:98217] 0.27
2016-06-20 14:57:28.507 App[4010:98217] 0.26
Author

陈昭

Posted on

2017-03-01

Updated on

2021-12-27

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Kommentare

You forgot to set the shortname for Disqus. Please set it in _config.yml.