项目中遇到的问题

数据解析问题:

由于后台返回的数据是一串字符串,而不是JSON格式.所以需要我们自己处理.
数据格式是这样的:key=value&key=value&key=value....

  • 首先我们要做的是创建一个数组,以&号为标志进行分割.
  • 使用initWithCapacity初始化一个字典.
  • 遍历数组,使用rangeOfString来搜索=的range信息.
  • 使用substringToIndex来截取到的数据作为key值.
  • 使用substringFromIndex来截取到的数据作为value值.
  • 最后使用setObjcet:forKey赋值.
    代码:
+ (NSMutableDictionary *)dataAnaly:(NSString *)string
{
    //以&进行分割
         NSArray * array = [string componentsSeparatedByString:@"&"];
    //如果你知道大概要放多少东西,那么最好用initWithCapacity,这个会提高程序内存运用效率。
         NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:array.count];
         
         for (NSString *str in array)
         {
                  
                  NSString *string = @"=";
                  //rangeOfString 前面的参数是要被搜索的字符串,后面的是要搜索的字符
                  //包含"="
                  NSRange range = [str rangeOfString:string];
             
             //返回一个字符串,这个字符串截取接受对象字符穿范围是从索引0到给定的索引index
            
             
                  NSString *keyStr = [str substringToIndex:range.location];
                  //NSLog(@"%@",keyStr);
             
              //返回一个字符串,这个字符串截取接受对象字符串范围是给定索引index到这个字符串的结尾
                  NSString *valueStr = [str substringFromIndex:range.location+1];
             
             
//             (1)setObject:forkey:中value是不能够为nil的;setValue:forKey:中value能够为nil,但是当value为nil的时候,会自动调用removeObject:forKey方法
//             (2)setValue:forKey:中key只能够是NSString类型,而setObject:forKey:的可以是任何类型
//             (3)setObject:forkey:中value是不能够为nil的,不然会报错。
                  
                  [result setObject:valueStr forKey:keyStr];
         }
         return result;
}

问题二:

因为是银行项目,涉及到金钱问题,所以只要涉及到输入密码的地方,都需要使用CFCA安全控件进行加密.
虽然CFCA使用很简单,但是第一次使用,也是需要踩坑的.
我们需要使用CFCA提供的CFCASIPInputField来创建这个控件.下面是它的几个属性设置.

     /** 代理 */
         _password_textField.sipInputFieldDelegate = self;
         /** 键盘动作 */
         _password_textField.bIsNeedKeyboardAnimation = NO;
         /** 最小长度 */
         _password_textField.nMinInputLength = 6;
         /** 最大长度 */
         _password_textField.nMaxInputLength = 16;
         /** 音效 */
         _password_textField.bHaveButtonClickSound = NO;
         /** RSA加密 */
         _password_textField.cipherType = SIP_KEYBOARD_CIPHER_TYPE_RSA;
         /** 原文加密 */
         _password_textField.emOutputValueType = OUTPUT_VALUE_TYPE_PLAIN_DATA;
         /** 键盘类型 */
         _password_textField.emSipKeyboardType = SIP_KEYBOARD_TYPE_COMPLETE;
         /** 是否加密 */
         _password_textField.bIsNeedEncrypt = YES;
         /** 服务器随机数 */
         _password_textField.strServerRandom = self.serverRandom_string;

看到服务器随机数没有,起初我认为是在创建控件之前,必须拿到的数据.然后傻傻的做了个控件创建延时.后来发现:

  dispatch_async(dispatch_get_main_queue(), ^{                                                              _password_textField.strServerRandom = self.serverRandom_string;
                                                        });

这么干也是可以的,真是哔了~

问题三:数据签名问题

签名机制如下:
对报文中出现签名域(signature)之外的所有数据元(数据元前后不能有空格)
采用key=value的形式按照key名称进行字典排序,然后以&作为连接符拼接成待签名串。其次,对待签名串使用SHA-1算法做摘要,再使用商户RSA私钥证书对摘要做签名操作(签名时算法选择SHA-1)。最后,对签名做Base64编码,将编码后的签名串放在签名(signature)表单域里和其他表单域一起通过HTTP Post的方式传输给支付平台。
这些算法网上都可以找到,一步步跟着来就好.最后程序只要加签就会崩溃,找了很多原因都没找到,所幸后台当时允许不加签测试.直到有一天我发现,原来是ras.pfx导入方式不正确.

我们需要

在这里导入,否则Xcode是识别不到的.之前都是拖拽进去的.

问题四:正则表达式

由于是金融类软件,需要登记身份信息.所以就会产生很多对数据的合法性判断.我认为这部分判断是在前台执行的,但是后台告诉我,他们那边处理.想着,在前台处理,输入正确,就会发送请求.输入不正确就不发送请求.可以优化一下程序.然后就加入了一些正则判断.结果就是测试的人员不能任意的注册账号了.(-_-),必须输入正确的手机号格式.

#pragma 正则匹配手机号
+ (BOOL)checkTelNumber:(NSString *) telNumber
{
         /**
          * 手机号码
          * 移动:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188
          * 联通:130,131,132,152,155,156,185,186
          * 电信:133,1349,153,180,189
          */
         NSString * MOBILE = @"^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$";
         /**
          10         * 中国移动:China Mobile
          11         * 134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188
          12         */
         NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d)\\d{7}$";
         /**
          15         * 中国联通:China Unicom
          16         * 130,131,132,152,155,156,183,185,186
          17         */
         NSString * CU = @"^1(3[0-2]|5[256]|8[356])\\d{8}$";
         /**
          20         * 中国电信:China Telecom
          21         * 133,1349,153,180,189
          22         */
         NSString * CT = @"^1((33|53|8[09])[0-9]|349)\\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];
         
         if (([regextestmobile evaluateWithObject:telNumber] == YES)
             || ([regextestcm evaluateWithObject:telNumber] == YES)
             || ([regextestct evaluateWithObject:telNumber] == YES)
             || ([regextestcu evaluateWithObject:telNumber] == YES))
         {
                  return YES;
         }
         else
         {
                  return NO;
         }
         
}
#pragma 正则匹配用户姓名,20位的中文或英文
+ (BOOL)checkUserName : (NSString *) userName
{
         
         //    NSString *pattern = @"^[A-Za-z0-9]{6,20}+$";
         //NSString *pattern = @"^([\u4e00-\u9fa5]+|([a-zA-Z]+\s?)+)$";
         NSString *pattern = @"^([\u4e00-\u9fa5]+|([a-zA-Z]+s?)+)$";
         NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
         BOOL isMatch = [pred evaluateWithObject:userName];
         return isMatch;
         
}
#pragma 正则匹配用户身份证号15或18位
+ (BOOL)checkUserIdCard: (NSString *) idCard
{
         BOOL flag;
         if (idCard.length <= 0) {
                  flag = NO;
                  return flag;
         }
         NSString *regex2 = @"^(\\d{14}|\\d{17})(\\d|[xX])$";
         NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex2];
         BOOL isMatch = [pred evaluateWithObject:idCard];
         return isMatch;
}
#pragma 正则匹配银行卡号是否正确
+ (BOOL) checkBankNumber:(NSString *) bankNumber{
         NSString *bankNum=@"^([0-9]{16}|[0-9]{19})$";
         NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",bankNum];
         BOOL isMatch = [pred evaluateWithObject:bankNumber];
         return isMatch;
}
#pragma 正则只能输入数字和字母
+ (BOOL) checkTeshuZifuNumber:(NSString *) CheJiaNumber{
         NSString *bankNum=@"^[A-Za-z0-9]+$";
         NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",bankNum];
         BOOL isMatch = [pred evaluateWithObject:CheJiaNumber];
         return isMatch;
}

还有一个关于金额输入的正则:

+ (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
         if (string.length == 0) {
                  return YES;
         }
         //第一个参数,被替换字符串的range,第二个参数,即将键入或者粘贴的string,返回的是改变过后的新str,即textfield的新的文本内容
         NSString *checkStr = [textField.text stringByReplacingCharactersInRange:range withString:string];
         //正则表达式
         NSString *regex = @"^\\-?([1-9]\\d*|0)(\\.\\d{0,2})?$";
         return [self isValid:checkStr withRegex:regex];
}
//检测改变过的文本是否匹配正则表达式,如果匹配表示可以键入,否则不能键入
+ (BOOL) isValid:(NSString*)checkStr withRegex:(NSString*)regex
{
         NSPredicate *predicte = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
         return [predicte evaluateWithObject:checkStr];
}

问题五:关于登录界面逻辑
我们做的项目,必须登录后才能使用功能.刚开始我使用导航栏来做登录界面跳转逻辑,在登陆界面隐藏导航栏,跳转后显示.会出现这样一个问题:退出登录后,登录界面有时候会显示导航栏.后来换了一种思路:通过改变rootViewController来实现登录逻辑.这样就不会产生任何问题.

登录界面:
self.window.rootViewController = loginVc;
登录成功:
 UIApplication.sharedApplication.delegate.window.rootViewController =tab;
退出登陆:
 UIApplication.sharedApplication.delegate.window.rootViewController =loginVc;

问题六:红包
项目后期提出发红包需求,发红包首先需要添加好友.经理要求我们自己用socket实现.我们跟后台讨论了好久,基本上每一个接口都要调试好多次,只要调通,就立马开始下一个接口的调试,直到打通一条线.然后回过头再去修补逻辑.
我使用的是GCDAnsySocket这个框架,使用的时候,需要绑定Ip与port.这里会有一个问题:wifi状态下和流量状态下,手机的IP地址是变化的,这里就需要用到RealReachability这个工具,来检测网络变化:

- (void)networkChanged:(NSNotification *)notification
{
         RealReachability *reachability = (RealReachability *)notification.object;
         ReachabilityStatus status = [reachability currentReachabilityStatus];
         ReachabilityStatus previousStatus = [reachability previousReachabilityStatus];
         NSLog(@"networkChanged, currentStatus:%@, previousStatus:%@", @(status), @(previousStatus));
         
         if (status == RealStatusNotReachable)
         {
               
         }
         
         if (status == RealStatusViaWiFi)
         {
                 
                  
                  Singleton *single = [Singleton shareData];
                  [self.udpSocket sendData:[single.operatorId dataUsingEncoding:NSUTF8StringEncoding]toHost:udpIP port:udpPort withTimeout:-1 tag:0];
                  
         }
         
         if (status == RealStatusViaWWAN)
         {
                  Singleton *single = [Singleton shareData];
                  [self.udpSocket sendData:[single.operatorId dataUsingEncoding:NSUTF8StringEncoding]toHost:udpIP port:udpPort withTimeout:-1 tag:0];
                  NSLog(@"这是手机Ip地址:%@",[GetWaanIp getIPAddress:YES]);
         }
}

当手机切换网络的时候,重新和服务器绑定.
消息列表:用来显示加好友信息和红包消息,暂未加入聊天.
消息列表使用plist进行存储,作为列表,存储的都是小批量数据,plist能够满足.
我们在存储消息的时候,先判断plist是否存在,如果没有,就创建.如果有,就先将plist中的数据解析成数组,将新消息(可能是之前的未读消息,如果未读,后台会一直推送)与plist中的消息,进行拼接,通过for循环剔除重复的消息内容,然后进行展示.
通过后台一个标识来判断这个消息是未读消息,还是已读消息,如果是未读,则会提示用户.如果是已读,需要我们将plist中这条消息改为已读状态(同时后台也不再推送这条消息,因为领取红包的时候,会向后台发送一个请求,改变信息的状态).
聊天界面则使用数据库进行存储,我使用的是WHC_SQLite.我们在消息列表中点击某一条消息的时候,才会往数据库插入这条数据.然后从数据库重新查询对应数据,进行展示.
发送红包的时候,在红包界面点击发送红包,使用代理在聊天界面调用一次sendMessage的方法,用来展示红包,同时将这条数据存入数据库.
红包的领取界面及发送界面,我们是仿照的QQ的样式.当点击红包时,这里有一个判断,判断是本人点击的红包还是对方点击的红包,如果是对方,那么会向后台发送一条红包状态请求和领取红包请求,如果是本人,只发送红包状态请求.领取红包成功,红包下方展示一条领取记录.同时,发红包的人,哪里也会显示这条领取记录.

问题七:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容