传值

在之前也写过正反向传值的文章,不过语言是Swift的(http://www.jianshu.com/p/be608f587e78 ),其实方法都差不多,现在用Objective-C实现,其中穿插正则表达式,原生json解析,category,原生联网请求(在XML解析一文中也使用过,这里会提到更高级的联网语法)等。联网记得修改plist文件
  很久没写过有意思的文章了,一直想把一个程序解释清楚,但是只要代码量一大就不知道从何说起,所以之前的好多文章都是直接放代码,代码中写清楚注释就OK了,现在再看一下之前的文章,如果不费点脑筋还是不易读懂的,好吧,一句话:懂点技术,但是表达一点不会。
  本例子界面是通过StoryBoard搭建的,具体如下图所示:

传值_第1张图片
登录界面
传值_第2张图片
注册界面

两个界面中的TextField都是自定义的,定制后的效果就是没有边框,然后在文本框下方有一条线,效果图如下:

传值_第3张图片
效果

自定义文本框代码:
.h文件中什么也不用写,这里放.m文件

#import "CDmMyTextField.h"

@implementation CDmMyTextField


- (void)drawRect:(CGRect)rect {
    
    //加下划线
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    [bezierPath moveToPoint:CGPointMake(0, rect.size.height)];
    [bezierPath addLineToPoint:CGPointMake(rect.size.width, rect.size.height)];
    [bezierPath stroke];
}

@end

界面搭建好了,接下来就用原来生成的ViewController写代码
.h文件也是空的,这里放.m文件

#import "ViewController.h"
#import "UIViewController+CDTool.h"
#import "CDRegViewController.h"
#import "CDSnsContext.h"

@interface ViewController () //

@property (weak, nonatomic) IBOutlet UITextField *userNameFiel;

@property (weak, nonatomic) IBOutlet UITextField *passWordField;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //消息中心传值
    //注册观察者
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(foo:) name:@"名字" object:nil];
    
}

//接收到消息进行处理
- (void)foo:(NSNotification *) sender{
    
    NSArray *array = sender.object;
    _userNameFiel.text = array[0];
    _passWordField.text = array[1];
    
}

//实现协议方法
//-(void)fillUsername:(NSString *)username password:(NSString *)password{
//    _userNameFiel.text = username;
//    _passWordField.text = password;
//}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)loginButtonClicked:(UIButton *)sender {
    
    NSString *uid = _userNameFiel.text;
    NSString *pwd = _passWordField.text;
    //通过字符串拼接的方式构造带查询参数的URL字符串
    NSString *urlStr = [NSString stringWithFormat:@"http://10.0.8.8/sns/my/login.php?username=%@&password=%@",uid,pwd];
    NSURL *url = [NSURL URLWithString:urlStr];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (!error) {
            //原生json解析
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            NSString *msg = dict[@"message"];
            
            //弹框提示
            [self cd_showAlertWithMessage:msg delay:1.5];
        }
        
    }];
    //resume非阻塞,异步
    [dataTask resume];
}

//该方法是在通过UISegue切换视图控制器的时候自动调用
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
   //CDRegViewController *regVC = segue.destinationViewController;
    
    //协议方式
//    regVC.delegate = self;
    
    //block方式
//    regVC.handler = ^(NSString *username, NSString *password){
//        _userNameFiel.text = username;
//        _passWordField.text = password;
//    };
    
    //单利方式
    //在viewWillAppear里面写
}

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
//    _userNameFiel.text = [CDSnsContext sharedSnsContext].username;
//    _passWordField.text = [CDSnsContext sharedSnsContext].password;
    
}

//dealloc方法中需要处理的事情
-(void)dealloc{
    //1.如果使用的NSTimer 那么要调用invalidate方法使其失效
    //2.如果使用了观察者 那么要移除观察者
    //3.如果使用系统底层的C函数申请了内存 那么在此处需要手动释放
    // - malloc() ---> free() --->nil
    // - CFXxxCreate() ---> CFRelease()
    
    //移除观察者
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

接着先把注册相关代码放上来,等下再解释
注册.h文件

#import 

//@protocol CDRegisterSuccessDelegate 

//- (void) fillUsername: (NSString *) username
//             password: (NSString *) password;

//@end

//此处将block类型重新命名成CDRegHandler
//以下代码如果出现CDRegHandler类型就代表这个block类型
typedef void (^CDRegHandler)(NSString *, NSString *);

@interface CDRegViewController : UIViewController

//@property (nonatomic , weak) id delegate;

//修饰符用法:
//assign - 基本数据类型、枚举、结构体/联合体都写assign,如果属性是一个指针,写assign相当于写weak
//strong - 对象指针通常都写strong,表示引用计数+1
//weak - 协议指针、插座变量、可能导致循环引用的地方都应该写weak
//copy - 确保指针指向不可变对象、获得对象的副本、Block类型写copy
//unsafe_unretained - 八辈子都不会用一次,不会自动将指针赋为nil,导致结果:可能产生野指针

//handler属性是block类型的属性,那么他可以保存一段代码
//在后面写的程序中可以使用handler属性来调用它保存的代码
@property (nonatomic , copy) CDRegHandler handler;

@end

注册.m文件

#import "CDRegViewController.h"
#import "UIViewController+CDTool.h"
#import "NSString+CDUtility.h"
#import "CDSnsContext.h"

@interface CDRegViewController () /**/

@property (weak, nonatomic) IBOutlet UITextField *userField;

@property (weak, nonatomic) IBOutlet UITextField *passField;

@property (weak, nonatomic) IBOutlet UITextField *passField2;

@property (weak, nonatomic) IBOutlet UITextField *emailField;

@end

@implementation CDRegViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)cancelButtonClicked:(UIButton *)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)OKAction:(UIButton *)sender {
   
/*
 放到补丁包中
    //正则表达式运用
    //创建谓词对象,限定字符串只能6-20位
    NSPredicate *pridicate = [NSPredicate predicateWithFormat:@"self matches %@",@"^\\w{6,20}$"];
    
 */
    
    NSString *uid = _userField.text;
    //开始验证
    if (![uid cd_matches:@"^\\w{6,20}$"]) {
        [self cd_showAlertWithMessage:@"无效的用户名" delay:1.5];
        return;
    }
    
    NSString *pwd = _passField.text;
    NSString *email = _emailField.text;
    //验证邮箱
//    if (![email cd_matches:@"^\\w+([-+.]\\w+)@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"]) {
//        [self cd_showAlertWithMessage:@"无效的邮箱" delay:1.5];
//        return;
//    }
    
    NSString *urlStr = [NSString stringWithFormat:@"http:10.0.8.8/sns/my/register.php?username=%@&password=%@&email=%@",uid,pwd,email];
    
    //URL中不能出现非ASCII码字符(中文,日语,希腊字母等Unicode字符都不能出现在URL中)
    //所以要先将含有非ASCII码的URL字符串中的那些字符转成百分号编码才是有效的URL字符串
    urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    
    NSURL *url= [NSURL URLWithString:urlStr];
    //联网Session高逼格方法(三种:默认,HTTPS,需要验证方式)
    //创建联网配置对象(三种配置:默认,无痕,后台)
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    //不用wifi或者电量过低就断网
    //config.discretionary = YES;
    //超时时间
    //config.timeoutIntervalForRequest = 5;
    //配置请求头
    //config setHTTPAdditionalHeaders:<#(NSDictionary * _Nullable)#>
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (!error) {
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            NSString *msg = dict[@"message"];
            
            NSString *code = dict[@"code"];
            //登陆成功会返回相应字符串
            if ([code isEqualToString:@"registered"]) {
                //反向传值,将用户名和密码传入登录界面的文本框
                
                //协议方式
//                [_delegate fillUsername:uid password:pwd];
                
                //block方式
                //传入对应的参数调用handler保存的代码
                //_handler(uid,pwd);
                
                //单利方式
                //[CDSnsContext sharedSnsContext].username = _userField.text;
                //[CDSnsContext sharedSnsContext].password = _passField.text;
                
                NSArray *array = @[_userField.text,_passField.text];
                
                //消息中心
                [[NSNotificationCenter defaultCenter] postNotificationName:@"名字" object:array userInfo:nil];
                
                [self dismissViewControllerAnimated:YES completion:nil];
            }
            else{
                //弹框提示
                [self cd_showAlertWithMessage:msg delay:1.5];
            }
        }
    }];
    
    [dataTask resume];
    
}

@end

在上面的代码中使用了协议方式、Block方式、单例方式、消息中心方式进行了传值,(协议方式、Block方式、单例方式都已经注释掉了,最后留下来的是消息中心的方式)注册成功后,注册后的账号和密码会传给登录界面,回到登录界面时就自动补全刚才注册的账号密码,至于什么是协议方式、Block方式、单例方式、消息中心方式可以看原来的文章“正反向传值”,只是Block在Swift中叫做闭包,实现方法差不多。
  其中单例方式需要创建单例对象,方法在代码注释中很详细,代码如下:
.h文件

#import 

@interface CDSnsContext : NSObject

//需要保存的属性
@property (nonatomic , copy) NSString *username;
@property (nonatomic , copy) NSString *password;

+ (instancetype) sharedSnsContext;

@end

.m文件

#import "CDSnsContext.h"

//实现单利的两个要点
//1.拒绝使用初始化方法创建对象
//2.通过类方法向外界提供唯一的实例

@implementation CDSnsContext

//1.1拒绝使用初始化方法创建对象
-(instancetype)init {
    
    //敢调用就敢抛异常
    @throw [NSException exceptionWithName:@"CDSnsContextInitNSException" reason:@"不能调用init方法创建CDSnsContext对象" userInfo:nil];
}

//1.2创建一个私有的初始化方法
-(instancetype)initPrivate{
    if (self = [super init]){
        
    }
    return self;
}

//2.通过类方法向外界提供唯一的实例
+ (instancetype)sharedSnsContext{
    
    //加了static的都是放到全局数据段的,拥有全局生命周期,独一无二(程序中永远只有一个本对象)
    static CDSnsContext *instance = nil;
    
    //为了解决多线程可以创建多个本对象问题,需要加上同步锁,保证多线程也只能创建一个本对象
    //同步锁
//    @synchronized (self) {
//        if (!instance) {
//            instance = [[self alloc] initPrivate];
//        }
//    }
    
    //此处使用一次派发效率会更高
    //一次派发
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!instance) {
            instance = [[self alloc] initPrivate];
        }
    });
   
    return instance;
}

@end

在代码中还是用到了一个方法“cd_showAlertWithMessage: delay:”和一个正则表达式的判断方法“cd_matches:”(邮箱判断的正则表达式来自谷歌,好像有点问题),第一个是弹出提示框并自动消失,为了让每个试图控制器都有这个功能,所以给ViewController写了一个category,同样的,第二个方法为了让每个字符串都具有正则校验功能,所以给NSString写了category

ViewController的category
.h文件

#import 

@interface UIViewController (CDTool)

-(void)cd_showAlertWithMessage: (NSString *) message
                      delay: (CGFloat) interval;

@end

.m文件

#import "UIViewController+CDTool.h"

@implementation UIViewController (CDTool)

-(void)cd_showAlertWithMessage: (NSString *) message
                      delay: (CGFloat) interval{
    
    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:message preferredStyle:UIAlertControllerStyleAlert];
        [self presentViewController:alert animated:YES completion:nil];
        //延迟操作
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            //提示框消失
            [self dismissViewControllerAnimated:YES completion:nil];
        });
    });
    
}

@end

NSString的category
.h文件

#import 

@interface NSString (CDUtility)

- (BOOL) cd_matches: (NSString *) regex;

@end

.m文件

#import "NSString+CDUtility.h"

@implementation NSString (CDUtility)

- (BOOL) cd_matches: (NSString *) regex{
    //正则表达式运用
    //创建谓词对象,限定字符串只能6-20位
    NSPredicate *pridicate = [NSPredicate predicateWithFormat:@"self matches %@",regex];
    return [pridicate evaluateWithObject:self];
}

@end

如何创建category?

首先创建一个Objective-C的文件


传值_第4张图片

再选中category,需要category的类,起个名字就OK了

传值_第5张图片

你可能感兴趣的:(传值)