- 可以在viewWillDisappear中判断下一个页面是pop、push还是present的
- 画圆的三种方式
- 获取当前控制器
- 消除警告
- UIButton中的TitleEdgeInsets使用
- 定位后的反编译和地区中文首字母缩写
- 更改 UINavigationBar 的返回键文字(同时保留右滑返回)
- NSDictionary/NSArray 转 JSON字符串
- KeyChain 保存密码
- 退出到最外层
- 关于 dispatch_barrier_async 的使用
1、可以在viewWillDisappear中判断下一个页面是pop、push还是present的
NSArray *viewControllers = self.navigationController.viewControllers;
if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
// View is disappearing because a new view controller was pushed onto the stack
NSLog(@"New view controller was pushed");
} else if ([viewControllers indexOfObject:self] == NSNotFound) {
// View is disappearing because it was popped from the stack
NSLog(@"View controller was popped");
}
else if (viewControllers.count <= 1) {
NSLog(@"View controller was present");
}
2、画圆的三种方式
1. 贝塞尔曲线画范围,Context上下文截取
- (UIImage *)makeRoundImage:(UIImage *)image {
CGFloat imageWidth = image.size.width;
CGFloat imageHeight = image.size.height;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(imageWidth, imageHeight), NO, 0.0);
UIGraphicsGetCurrentContext();
CGFloat radius = (imageWidth < imageHeight?imageHeight:imageHeight)*0.5;
UIBezierPath *Bezier = [UIBezierPath bezierPathWithArcCenter:CGPointMake(imageWidth*0.5, imageHeight*0.5) radius:radius startAngle:0 endAngle:M_PI*2 clockwise:YES];
[Bezier stroke];
[Bezier addClip];
[image drawInRect:CGRectMake(0, 0, imageWidth, imageHeight)];
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultImage;
}
2. layer.cornerRadius设置为高度的一半,前提是宽高相同
UIImageView *imageView = [UIImageView new];
imageView.layer.masksToBounds = YES;
imageView.layer.cornerRadius = CGRectGetWidth(imageView.bounds)/2.0;
3. 直接通过sb跟xib设置,不过需要设置成固定值
http://www.360doc.com/content/15/0128/17/20918780_444509231.shtml
3、获取当前控制器
+ (UIViewController *)getCurrentVC
{
UIViewController *result = nil;
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
//app默认windowLevel是UIWindowLevelNormal,如果不是,找到UIWindowLevelNormal的
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
id nextResponder = nil;
UIViewController *appRootVC=window.rootViewController;
// 如果是present上来的appRootVC.presentedViewController 不为nil
if (appRootVC.presentedViewController) {
nextResponder = appRootVC.presentedViewController;
}else{
UIView *frontView = [[window subviews] objectAtIndex:0];
nextResponder = [frontView nextResponder];
}
if ([nextResponder isKindOfClass:[UITabBarController class]]){
UITabBarController * tabbar = (UITabBarController *)nextResponder;
UINavigationController * nav = (UINavigationController *)tabbar.viewControllers[tabbar.selectedIndex];
// UINavigationController * nav = tabbar.selectedViewController ; 上下两种写法都行
result=nav.childViewControllers.lastObject;
}else if ([nextResponder isKindOfClass:[UINavigationController class]]){
UIViewController * nav = (UIViewController *)nextResponder;
result = nav.childViewControllers.lastObject;
}else{
result = nextResponder;
}
return result;
}
4、消除警告
http://www.jianshu.com/p/eb03e20f7b1c
5、UIButton中的TitleEdgeInsets使用
UIButton中的ImageEdgeInsets与TitleEdgeInsets都是针对当前位置生效的,即设置UIEdgeInsetsMake(a, b, c, d)则意味着向上偏移a、向左偏移b、向下偏移c、向右偏移d
6、定位后的反编译和地区中文首字母缩写
CLLocation *location = locations.lastObject;
CLGeocoder *revGeo = [[CLGeocoder alloc] init];
[revGeo reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
NSDictionary *dict = [[placemarks objectAtIndex:0] addressDictionary];
NSString *state = dict[@"State"];
NSMutableString *str = [NSMutableString stringWithString:state];
CFStringTransform((CFMutableStringRef) str, NULL, kCFStringTransformMandarinLatin, NO);
CFStringTransform((CFMutableStringRef)str, NULL, kCFStringTransformStripDiacritics, NO);
NSString *pinYin = [str capitalizedString];
NSArray *pinyinArr = [pinYin componentsSeparatedByString:@" "];
NSMutableString *totalString = [NSMutableString string];
for (int i=0; i<pinyinArr.count; i++) {
if (i != pinyinArr.count-1 || (![pinyinArr[i] isEqualToString:@"Sheng"] && [pinyinArr[i] isEqualToString:@"Shi"])) {
NSString *nowState = pinyinArr[i];
[totalString appendString:[nowState substringToIndex:1]];
}
}
NSLog(@"%@",totalString);
}];
7、更改 UINavigationBar 的返回键文字(同时保留右滑返回)
目前为止,查到了许多种做法,然而实验之后发现,可行的暂且是有一种
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleDone target:self action:nil];
这里更改的是下一个 Push 过去的控制器的返回键的文字,图案的样式保留。
8、NSDictionary/NSArray 转 JSON字符串
+ (NSString *)jsonStringFormDict:(NSDictionary *)dict {
NSMutableString *jsonString = [NSMutableString string];
[jsonString appendString:@"{"];
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if (jsonString.length > 1) {
[jsonString appendString:@","];
}
[jsonString appendFormat:@"\"%@\":",key];
if ([obj isKindOfClass:[NSArray class]]) {
[jsonString appendString:[self jsonStringFormArray:obj]];
}
else {
if ([obj isKindOfClass:[NSDictionary class]]) {
[jsonString appendString:[self jsonStringFormDict:obj]];
}
else {
[jsonString appendFormat:@"\"%@\"",obj];
}
}
}];
[jsonString appendString:@"}"];
return jsonString;
}
+ (NSString *)jsonStringFormArray:(NSArray *)array {
NSMutableString *jsonString = [NSMutableString string];
[jsonString appendString:@"["];
for (int i=0; i<array.count; i++) {
if (i != 0) {
[jsonString appendString:@","];
}
if ([array[i] isKindOfClass:[NSDictionary class]]) {
[jsonString appendString:[self jsonStringFormDict:array[i]]];
}
else {
if ([array[i] isKindOfClass:[NSArray class]]) {
[jsonString appendString:[self jsonStringFormArray:array[i]]];
}
else {
[jsonString appendFormat:@"\"%@\"",array[i]];
}
}
}
[jsonString appendString:@"]"];
return jsonString;
}
9、KeyChain 保存密码
- 打开 Capabilities 中的 Keychain Sharing 开关,否则在 iOS10 中会崩溃。
- 导入 Security.framework
- 编写 KeyChain 文件
//
// XWSDKeyChain.h
// XWSDCarLoan
//
// Created by chenjintian on 17/2/13.
// Copyright © 2017年 CJT. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface XWSDKeyChain : NSObject
+ (void)save:(NSString *)service data:(id)data;
+ (id)load:(NSString *)service;
+ (void)delete:(NSString *)service;
@end
//
// XWSDKeyChain.m
// XWSDCarLoan
//
// Created by chenjintian on 17/2/13.
// Copyright © 2017年 CJT. All rights reserved.
//
#import "XWSDKeyChain.h"
#import <Security/Security.h>
@implementation XWSDKeyChain
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassGenericPassword,(id)kSecClass,
service, (id)kSecAttrService,
service, (id)kSecAttrAccount,
(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
nil];
}
+ (void)save:(NSString *)service data:(id)data {
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
//Delete old item before add new item
SecItemDelete((CFDictionaryRef)keychainQuery);
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}
+ (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
//Configure the search setting
//Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", service, e);
} @finally {
}
}
if (keyData)
CFRelease(keyData);
return ret;
}
+ (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((CFDictionaryRef)keychainQuery);
}
@end
10、退出到最外层
presentingViewController:
UIViewController *vc = self;
while (vc.presentingViewController) {
vc = vc.presentingViewController;
}
[vc dismissViewControllerAnimated:YES completion:nil];
pushViewController:
[self.navigationController popToRootViewControllerAnimated:YES];
11、关于 dispatch_barrier_async 的使用
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-1");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-2");
});
dispatch_barrier_async(concurrentQueue, ^(){
NSLog(@"dispatch-barrier");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-3");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-4");
});
代码是拷贝的,理解是自己的。
barrier 的翻译是栅栏,在代码中的意思就是用来分割、确定线程,在上面的输出中,前面两个输出1、2顺序不定,第三个一定为dispatch-barrier,第四五个输出3、4顺序也不定。此为分割效果
也可以放在最后,作为一个前面的线程都处理完毕的标记。