From 5a2d390dd1b060969425ab917cb1533c98e8199a Mon Sep 17 00:00:00 2001 From: DarkHorse1919 Date: Wed, 24 Jun 2015 11:34:45 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E4=B8=A4=E4=B8=AA=E7=B1=BB?= =?UTF-8?q?=E5=88=AB:UIViewController+BackButtonHandler;NSString+RegexCate?= =?UTF-8?q?gory.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NSString/NSString+RegexCategory.h | 154 +++++++++ .../NSString/NSString+RegexCategory.m | 308 ++++++++++++++++++ .../UIViewController+BackButtonHandler.h | 36 ++ .../UIViewController+BackButtonHandler.m | 64 ++++ IOS-Categories.xcodeproj/project.pbxproj | 12 + 5 files changed, 574 insertions(+) create mode 100644 Categories/Foundation/NSString/NSString+RegexCategory.h create mode 100644 Categories/Foundation/NSString/NSString+RegexCategory.m create mode 100644 Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.h create mode 100644 Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.m diff --git a/Categories/Foundation/NSString/NSString+RegexCategory.h b/Categories/Foundation/NSString/NSString+RegexCategory.h new file mode 100644 index 0000000..d363b18 --- /dev/null +++ b/Categories/Foundation/NSString/NSString+RegexCategory.h @@ -0,0 +1,154 @@ +// +// NSString+RegexCategory.h +// IOS-Categories +// +// Created by KevinHM on 15/6/24. +// Copyright (c) 2015年 KevinHM. All rights reserved. +// https://github.com/KevinHM +// + +#import +/** + * 正则表达式简单说明 + * 语法: + . 匹配除换行符以外的任意字符 + \w 匹配字母或数字或下划线或汉字 + \s 匹配任意的空白符 + \d 匹配数字 + \b 匹配单词的开始或结束 + ^ 匹配字符串的开始 + $ 匹配字符串的结束 + * 重复零次或更多次 + + 重复一次或更多次 + ? 重复零次或一次 + {n} 重复n次 + {n,} 重复n次或更多次 + {n,m} 重复n到m次 + \W 匹配任意不是字母,数字,下划线,汉字的字符 + \S 匹配任意不是空白符的字符 + \D 匹配任意非数字的字符 + \B 匹配不是单词开头或结束的位置 + [^x] 匹配除了x以外的任意字符 + [^aeiou]匹配除了aeiou这几个字母以外的任意字符 + *? 重复任意次,但尽可能少重复 + +? 重复1次或更多次,但尽可能少重复 + ?? 重复0次或1次,但尽可能少重复 + {n,m}? 重复n到m次,但尽可能少重复 + {n,}? 重复n次以上,但尽可能少重复 + \a 报警字符(打印它的效果是电脑嘀一声) + \b 通常是单词分界位置,但如果在字符类里使用代表退格 + \t 制表符,Tab + \r 回车 + \v 竖向制表符 + \f 换页符 + \n 换行符 + \e Escape + \0nn ASCII代码中八进制代码为nn的字符 + \xnn ASCII代码中十六进制代码为nn的字符 + \unnnn Unicode代码中十六进制代码为nnnn的字符 + \cN ASCII控制字符。比如\cC代表Ctrl+C + \A 字符串开头(类似^,但不受处理多行选项的影响) + \Z 字符串结尾或行尾(不受处理多行选项的影响) + \z 字符串结尾(类似$,但不受处理多行选项的影响) + \G 当前搜索的开头 + \p{name} Unicode中命名为name的字符类,例如\p{IsGreek} + (?>exp) 贪婪子表达式 + (?-exp) 平衡组 + (?im-nsx:exp) 在子表达式exp中改变处理选项 + (?im-nsx) 为表达式后面的部分改变处理选项 + (?(exp)yes|no) 把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no + (?(exp)yes) 同上,只是使用空表达式作为no + (?(name)yes|no) 如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no + (?(name)yes) 同上,只是使用空表达式作为no + + 捕获 + (exp) 匹配exp,并捕获文本到自动命名的组里 + (?exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) + (?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号 + 零宽断言 + (?=exp) 匹配exp前面的位置 + (?<=exp) 匹配exp后面的位置 + (?!exp) 匹配后面跟的不是exp的位置 + (? + +@interface NSString (RegexCategory) +/** + * 手机号码的有效性:分电信、联通、移动和小灵通 + */ +- (BOOL)isMobileNumberClassification; +/** + * 手机号有效性 + */ +- (BOOL)isMobileNumber; + +/** + * 邮箱的有效性 + */ +- (BOOL)isEmailAddress; + +/** + * 简单的身份证有效性 + * + */ +- (BOOL)simpleVerifyIdentityCardNum; + +/** + * 精确的身份证号码有效性检测 + * + * @param value 身份证号 + */ ++ (BOOL)accurateVerifyIDCardNumber:(NSString *)value; + +/** + * 车牌号的有效性 + */ +- (BOOL)isCarNumber; + +/** + * 银行卡的有效性 + */ +- (BOOL)bankCardluhmCheck; + +/** + * IP地址有效性 + */ +- (BOOL)isIPAddress; + +/** + * Mac地址有效性 + */ +- (BOOL)isMacAddress; + +//#pragma mark - 这部分可以根据您的应用视情况定规则,下面为示例代码 +///** +// * 是否纯数字 +// */ +//- (BOOL)isDigitalAll; +// +///** +// * 用户名 +// */ +//- (BOOL) validateUserName; +// +///** +// * 昵称 +// */ +//- (BOOL) validateNickname; +// +///** +// * 密码 +// */ +//- (BOOL) validatePassword; + +@end diff --git a/Categories/Foundation/NSString/NSString+RegexCategory.m b/Categories/Foundation/NSString/NSString+RegexCategory.m new file mode 100644 index 0000000..d0171c0 --- /dev/null +++ b/Categories/Foundation/NSString/NSString+RegexCategory.m @@ -0,0 +1,308 @@ +// +// NSString+RegexCategory.h +// IOS-Categories +// +// Created by KevinHM on 15/6/24. +// Copyright (c) 2015年 KevinHM. All rights reserved. +// https://github.com/KevinHM +// + +#import "NSString+RegexCategory.h" + +@implementation NSString (RegexCategory) + +//手机号分服务商 +- (BOOL)isMobileNumberClassification{ + /** + * 手机号码 + * 移动:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188,1705 + * 联通:130,131,132,152,155,156,185,186,1709 + * 电信:133,1349,153,180,189,1700 + */ + // NSString * MOBILE = @"^1((3//d|5[0-35-9]|8[025-9])//d|70[059])\\d{7}$";//总况 + + /** + 10 * 中国移动:China Mobile + 11 * 134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188,1705 + 12 */ + NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d|705)\\d{7}$"; + /** + 15 * 中国联通:China Unicom + 16 * 130,131,132,152,155,156,185,186,1709 + 17 */ + NSString * CU = @"^1((3[0-2]|5[256]|8[56])\\d|709)\\d{7}$"; + /** + 20 * 中国电信:China Telecom + 21 * 133,1349,153,180,189,1700 + 22 */ + NSString * CT = @"^1((33|53|8[09])\\d|349|700)\\d{7}$"; + + + /** + 25 * 大陆地区固话及小灵通 + 26 * 区号:010,020,021,022,023,024,025,027,028,029 + 27 * 号码:七位或八位 + 28 */ + NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$"; + + + // NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE]; + NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM]; + NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU]; + NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT]; + NSPredicate *regextestphs = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",PHS]; + + if (([regextestcm evaluateWithObject:self] == YES) + || ([regextestct evaluateWithObject:self] == YES) + || ([regextestcu evaluateWithObject:self] == YES) + || ([regextestphs evaluateWithObject:self] == YES)) + { + return YES; + } + else + { + return NO; + } +} + +//手机号有效性 +- (BOOL)isMobileNumber{ + /** + * 手机号以13、15、18、170开头,8个 \d 数字字符 + * 小灵通 区号:010,020,021,022,023,024,025,027,028,029 还有未设置的新区号xxx + */ + NSString *mobileNoRegex = @"^1((3\\d|5[0-35-9]|8[025-9])\\d|70[059])\\d{7}$";//除4以外的所有个位整数,不能使用[^4,\\d]匹配,这里是否iOS Bug? + NSString *phsRegex =@"^0(10|2[0-57-9]|\\d{3})\\d{7,8}$"; + NSPredicate *regextestMobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",mobileNoRegex]; + NSPredicate *regextestPhs = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",phsRegex]; + BOOL ret = [regextestMobile evaluateWithObject:self]; + BOOL ret1 = [regextestPhs evaluateWithObject:self]; + + return (ret || ret1); +} + +//邮箱 +- (BOOL)isEmailAddress{ + NSString *emailRegex = @"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; + NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",emailRegex]; + return [emailTest evaluateWithObject:self]; +} + +//身份证号 +- (BOOL) simpleVerifyIdentityCardNum +{ + NSString *regex2 = @"^(\\d{14}|\\d{17})(\\d|[xX])$"; + NSPredicate *identityCardPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex2]; + return [identityCardPredicate evaluateWithObject:self]; +} + +//精确的身份证号码有效性检测 ++ (BOOL)accurateVerifyIDCardNumber:(NSString *)value { + value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + int length =0; + if (!value) { + return NO; + }else { + length = (int)value.length; + + if (length !=15 && length !=18) { + return NO; + } + } + // 省份代码 + NSArray *areasArray =@[@"11",@"12", @"13",@"14", @"15",@"21", @"22",@"23", @"31",@"32", @"33",@"34", @"35",@"36", @"37",@"41", @"42",@"43", @"44",@"45", @"46",@"50", @"51",@"52", @"53",@"54", @"61",@"62", @"63",@"64", @"65",@"71", @"81",@"82", @"91"]; + + NSString *valueStart2 = [value substringToIndex:2]; + BOOL areaFlag =NO; + for (NSString *areaCode in areasArray) { + if ([areaCode isEqualToString:valueStart2]) { + areaFlag =YES; + break; + } + } + + if (!areaFlag) { + return false; + } + + + NSRegularExpression *regularExpression; + NSUInteger numberofMatch; + + int year =0; + switch (length) { + case 15: + year = [value substringWithRange:NSMakeRange(6,2)].intValue +1900; + + if (year %4 ==0 || (year %100 ==0 && year %4 ==0)) { + + regularExpression = [[NSRegularExpression alloc] initWithPattern:@"^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$" + options:NSRegularExpressionCaseInsensitive + error:nil];//测试出生日期的合法性 + }else { + regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$" + options:NSRegularExpressionCaseInsensitive + error:nil];//测试出生日期的合法性 + } + numberofMatch = [regularExpression numberOfMatchesInString:value + options:NSMatchingReportProgress + range:NSMakeRange(0, value.length)]; + + if(numberofMatch >0) { + return YES; + }else { + return NO; + } + case 18: + year = [value substringWithRange:NSMakeRange(6,4)].intValue; + if (year %4 ==0 || (year %100 ==0 && year %4 ==0)) { + + regularExpression = [[NSRegularExpression alloc] initWithPattern:@"^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$" + options:NSRegularExpressionCaseInsensitive + error:nil];//测试出生日期的合法性 + }else { + regularExpression = [[NSRegularExpression alloc] initWithPattern:@"^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$" + options:NSRegularExpressionCaseInsensitive + error:nil];//测试出生日期的合法性 + } + numberofMatch = [regularExpression numberOfMatchesInString:value + options:NSMatchingReportProgress + range:NSMakeRange(0, value.length)]; + + if(numberofMatch >0) { + int S = ([value substringWithRange:NSMakeRange(0,1)].intValue + [value substringWithRange:NSMakeRange(10,1)].intValue) *7 + ([value substringWithRange:NSMakeRange(1,1)].intValue + [value substringWithRange:NSMakeRange(11,1)].intValue) *9 + ([value substringWithRange:NSMakeRange(2,1)].intValue + [value substringWithRange:NSMakeRange(12,1)].intValue) *10 + ([value substringWithRange:NSMakeRange(3,1)].intValue + [value substringWithRange:NSMakeRange(13,1)].intValue) *5 + ([value substringWithRange:NSMakeRange(4,1)].intValue + [value substringWithRange:NSMakeRange(14,1)].intValue) *8 + ([value substringWithRange:NSMakeRange(5,1)].intValue + [value substringWithRange:NSMakeRange(15,1)].intValue) *4 + ([value substringWithRange:NSMakeRange(6,1)].intValue + [value substringWithRange:NSMakeRange(16,1)].intValue) *2 + [value substringWithRange:NSMakeRange(7,1)].intValue *1 + [value substringWithRange:NSMakeRange(8,1)].intValue *6 + [value substringWithRange:NSMakeRange(9,1)].intValue *3; + int Y = S %11; + NSString *M =@"F"; + NSString *JYM =@"10X98765432"; + M = [JYM substringWithRange:NSMakeRange(Y,1)];// 判断校验位 + if ([M isEqualToString:[value substringWithRange:NSMakeRange(17,1)]]) { + return YES;// 检测ID的校验位 + }else { + return NO; + } + + }else { + return NO; + } + default: + return NO; + } +} + +//车牌 +- (BOOL)isCarNumber{ + NSString *carRegex = @"^[\u4e00-\u9fff]{1}[a-zA-Z]{1}[a-zA-Z_0-9]{4}[a-zA-Z_0-9_\u4e00-\u9fff]$";//其中\u4e00-\u9fa5表示unicode编码中汉字已编码部分,\u9fa5-\u9fff是保留部分,将来可能会添加 + NSPredicate *carTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",carRegex]; + return [carTest evaluateWithObject:self]; +} + +/** 银行卡号有效性问题Luhn算法 + * 现行 16 位银联卡现行卡号开头 6 位是 622126~622925 之间的,7 到 15 位是银行自定义的, + * 可能是发卡分行,发卡网点,发卡序号,第 16 位是校验码。 + * 16 位卡号校验位采用 Luhm 校验方法计算: + * 1,将未带校验位的 15 位卡号从右依次编号 1 到 15,位于奇数位号上的数字乘以 2 + * 2,将奇位乘积的个十位全部相加,再加上所有偶数位上的数字 + * 3,将加法和加上校验位能被 10 整除。 + */ +- (BOOL)bankCardluhmCheck{ + NSString * lastNum = [[self substringFromIndex:(self.length-1)] copy];//取出最后一位 + NSString * forwardNum = [[self substringToIndex:(self.length -1)] copy];//前15或18位 + + NSMutableArray * forwardArr = [[NSMutableArray alloc] initWithCapacity:0]; + for (int i=0; i -1; i--) {//前15位或者前18位倒序存进数组 + [forwardDescArr addObject:forwardArr[i]]; + } + + NSMutableArray * arrOddNum = [[NSMutableArray alloc] initWithCapacity:0];//奇数位*2的积 < 9 + NSMutableArray * arrOddNum2 = [[NSMutableArray alloc] initWithCapacity:0];//奇数位*2的积 > 9 + NSMutableArray * arrEvenNum = [[NSMutableArray alloc] initWithCapacity:0];//偶数位数组 + + for (int i=0; i< forwardDescArr.count; i++) { + NSInteger num = [forwardDescArr[i] intValue]; + if (i%2) {//偶数位 + [arrEvenNum addObject:[NSNumber numberWithInteger:num]]; + }else{//奇数位 + if (num * 2 < 9) { + [arrOddNum addObject:[NSNumber numberWithInteger:num * 2]]; + }else{ + NSInteger decadeNum = (num * 2) / 10; + NSInteger unitNum = (num * 2) % 10; + [arrOddNum2 addObject:[NSNumber numberWithInteger:unitNum]]; + [arrOddNum2 addObject:[NSNumber numberWithInteger:decadeNum]]; + } + } + } + + __block NSInteger sumOddNumTotal = 0; + [arrOddNum enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) { + sumOddNumTotal += [obj integerValue]; + }]; + + __block NSInteger sumOddNum2Total = 0; + [arrOddNum2 enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) { + sumOddNum2Total += [obj integerValue]; + }]; + + __block NSInteger sumEvenNumTotal =0 ; + [arrEvenNum enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) { + sumEvenNumTotal += [obj integerValue]; + }]; + + NSInteger lastNumber = [lastNum integerValue]; + + NSInteger luhmTotal = lastNumber + sumEvenNumTotal + sumOddNum2Total + sumOddNumTotal; + + return (luhmTotal%10 ==0)?YES:NO; +} + +- (BOOL)isIPAddress{ + NSString * ipAddRegex = @"(\\d{1,3}[.]){3}\\d{1,3}"; + NSPredicate *ipAddTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",ipAddRegex]; + return [ipAddTest evaluateWithObject:self]; +} + +- (BOOL)isMacAddress{ + NSString * macAddRegex = @"([A-Fa-f\\d]{2}:){5}[A-Fa-f\\d]{2}"; + NSPredicate * macAddTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",macAddRegex]; + return [macAddTest evaluateWithObject:self]; +} + +//#pragma mark - 这部分可以根据您的应用视情况定规则,下面为示例代码 +////纯数字(8位) +//- (BOOL)isDigitalAll{ +// NSString * digitalRegex = @"^[0-9]{0,8}+$"; +// NSPredicate *digitalPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",digitalRegex]; +// return [digitalPredicate evaluateWithObject:self]; +//} +////用户名(2到12个字符:包含中文、英文、数字、字母、点与下划线%+-等) +//- (BOOL) validateUserName +//{ +// NSString *userNameRegex = @"^[\u4e00-\u9fffA-Za-z0-9._%+-]{2,12}$"; +// NSPredicate *userNamePredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",userNameRegex]; +// BOOL B = [userNamePredicate evaluateWithObject:self]; +// return B; +//} +////昵称(4到8个字符:包含中文、英文、数字、字母、点与下划线%+-等) +//- (BOOL) validateNickname +//{ +// NSString *nicknameRegex = @"^[\u4e00-\u9fffA-Za-z0-9._%+-]{4,8}$"; +// NSPredicate *passWordPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",nicknameRegex]; +// return [passWordPredicate evaluateWithObject:self]; +//} +// +////密码(6位数字与字母) +//- (BOOL) validatePassword +//{ +// NSString *passWordRegex = @"^[a-zA-Z0-9]{6}$"; +// NSPredicate *passWordPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",passWordRegex]; +// return [passWordPredicate evaluateWithObject:self]; +//} + +@end diff --git a/Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.h b/Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.h new file mode 100644 index 0000000..1f75538 --- /dev/null +++ b/Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.h @@ -0,0 +1,36 @@ +// UIViewController+BackButtonHandler.h +// +// Created by Sergey Nikitenko on 10/1/13. +// Copyright 2013 Sergey Nikitenko. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import + +@protocol BackButtonHandlerProtocol +@optional +// Override this method in UIViewController derived class to handle 'Back' button click +-(BOOL)navigationShouldPopOnBackButton; +@end + +@interface UIViewController (BackButtonHandler) + +@end + diff --git a/Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.m b/Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.m new file mode 100644 index 0000000..ed2a81b --- /dev/null +++ b/Categories/UIKit/UIViewController/UIViewController+BackButtonHandler.m @@ -0,0 +1,64 @@ +// +// UIViewController+BackButtonHandler.m +// +// Created by Sergey Nikitenko on 10/1/13. +// Copyright 2013 Sergey Nikitenko. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "UIViewController+BackButtonHandler.h" + +@implementation UIViewController (BackButtonHandler) + +@end + +@implementation UINavigationController (ShouldPopOnBackButton) + +- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { + + if([self.viewControllers count] < [navigationBar.items count]) { + return YES; + } + + BOOL shouldPop = YES; + UIViewController* vc = [self topViewController]; + if([vc respondsToSelector:@selector(navigationShouldPopOnBackButton)]) { + shouldPop = [vc navigationShouldPopOnBackButton]; + } + + if(shouldPop) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self popViewControllerAnimated:YES]; + }); + } else { + // Workaround for iOS7.1. Thanks to @boliva - http://stackoverflow.com/posts/comments/34452906 + for(UIView *subview in [navigationBar subviews]) { + if(subview.alpha < 1.) { + [UIView animateWithDuration:.25 animations:^{ + subview.alpha = 1.; + }]; + } + } + } + + return NO; +} + +@end diff --git a/IOS-Categories.xcodeproj/project.pbxproj b/IOS-Categories.xcodeproj/project.pbxproj index 6096086..107bf79 100644 --- a/IOS-Categories.xcodeproj/project.pbxproj +++ b/IOS-Categories.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 798256171B3A57340033A0C1 /* UIViewController+BackButtonHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 798256161B3A57340033A0C1 /* UIViewController+BackButtonHandler.m */; }; + 7982561A1B3A59060033A0C1 /* NSString+RegexCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = 798256191B3A59060033A0C1 /* NSString+RegexCategory.m */; }; A202D9621B0F6C4400EAB199 /* NSDate+Reporting.m in Sources */ = {isa = PBXBuildFile; fileRef = A202D9611B0F6C4400EAB199 /* NSDate+Reporting.m */; }; A202D9651B0F6DF900EAB199 /* NSString+MIME.m in Sources */ = {isa = PBXBuildFile; fileRef = A202D9641B0F6DF900EAB199 /* NSString+MIME.m */; }; A202D96B1B0F6FA400EAB199 /* UIBarButtonItem+Action.m in Sources */ = {isa = PBXBuildFile; fileRef = A202D96A1B0F6FA400EAB199 /* UIBarButtonItem+Action.m */; }; @@ -323,6 +325,10 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 798256151B3A57340033A0C1 /* UIViewController+BackButtonHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+BackButtonHandler.h"; sourceTree = ""; }; + 798256161B3A57340033A0C1 /* UIViewController+BackButtonHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+BackButtonHandler.m"; sourceTree = ""; }; + 798256181B3A59060033A0C1 /* NSString+RegexCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RegexCategory.h"; sourceTree = ""; }; + 798256191B3A59060033A0C1 /* NSString+RegexCategory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RegexCategory.m"; sourceTree = ""; }; A202D9601B0F6C4400EAB199 /* NSDate+Reporting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+Reporting.h"; sourceTree = ""; }; A202D9611B0F6C4400EAB199 /* NSDate+Reporting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+Reporting.m"; sourceTree = ""; }; A202D9631B0F6DF900EAB199 /* NSString+MIME.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+MIME.h"; sourceTree = ""; }; @@ -1953,6 +1959,8 @@ BCB79A041AFDE19200C12525 /* NSString+Contains.m */, A202D9631B0F6DF900EAB199 /* NSString+MIME.h */, A202D9641B0F6DF900EAB199 /* NSString+MIME.m */, + 798256181B3A59060033A0C1 /* NSString+RegexCategory.h */, + 798256191B3A59060033A0C1 /* NSString+RegexCategory.m */, ); path = NSString; sourceTree = ""; @@ -2128,6 +2136,8 @@ BCB79A071AFDE2F700C12525 /* UIViewController+DDPopUpViewController.m */, A2958CB81B357AEF00D7AA0F /* UIViewController+StoreKit.h */, A2958CB91B357AEF00D7AA0F /* UIViewController+StoreKit.m */, + 798256151B3A57340033A0C1 /* UIViewController+BackButtonHandler.h */, + 798256161B3A57340033A0C1 /* UIViewController+BackButtonHandler.m */, ); path = UIViewController; sourceTree = ""; @@ -2815,6 +2825,7 @@ A2768FD31A5518C400E03C90 /* UIView+Toast.m in Sources */, A202D9861B0F7D2A00EAB199 /* MKMapView+ZoomLevel.m in Sources */, A2681A411A75C788009BA7EE /* NSData+Base64.m in Sources */, + 798256171B3A57340033A0C1 /* UIViewController+BackButtonHandler.m in Sources */, A2958D301B359C3300D7AA0F /* UIImageView+GeometryConversion.m in Sources */, A281FBF91AC813B8009040DA /* UITextViewDemoViewController.m in Sources */, A202D9C01B1038DB00EAB199 /* UIBarButtonItemDemoViewController.m in Sources */, @@ -2903,6 +2914,7 @@ A284C1491AEBCFB000D90ED5 /* NSIndexPathDemoViewController.m in Sources */, A202D9A21B102A4F00EAB199 /* NSNumber+Round.m in Sources */, A202D98C1B0F7D7900EAB199 /* MKMapViewDemoViewController.m in Sources */, + 7982561A1B3A59060033A0C1 /* NSString+RegexCategory.m in Sources */, A2958CF01B35838100D7AA0F /* NSPersistentStoreCoordinatorDemoViewController.m in Sources */, A281FBCB1AC8130E009040DA /* UIDeviceDemoViewController.m in Sources */, A28BE3381A3E9FDC005C4AC6 /* UIView+Debug.m in Sources */,