iOS+PHP实现登录功能

2024/5/3 6:13:47

  近期在做app开发的时候,因为要用到app登录功能,就自己写了个简单的iOS+PHP实现登录功能的demo,经过运行能够通过登录测试。

  在开发过程中,也是碰到了各种各样的问题,经过不断的调试和改变方法,终于将所有的坑都基本上填满了,因此,将最终完整版的代码及相关流程记录在此,供自己及其它需要的人查阅使用。

一、一些约定条件

  Mac OS真的是一个太太太封闭的系统环境了,封闭到我已经测试了N中办法,都没办法成功搭建后台服务器——不管是使用集成软件(如MAMP或者XAMPP),还是自行下载MySQL和MyAdmin客户端安装。有的时候Apache无法正常启动,有时候MySQL又故障掉了,更悲哀的是,真机测试时,客户端上输入内容后,无法正常与服务器通信!逼不得已,就只能放弃了,最终采用Windows的WIN7系统的电脑做后台服务器,然后与测试用的手机、编程用的Mac电脑处于同一无线局域网下。==如果哪位同仁能告知如何在MacBook上搭建后台服务器且能正常工作,欢迎不吝赐教,鄙人万分感激!==

  当在装有WIN 7系统的电脑上配置服务器时,我使用的是WAMP集成软件,数据库和表的编辑操作使用的是SQLyog软件,这样可以有效的创建、修改表的内容。==注意,在WIN7的电脑上搭建完后台并创建好数据库之后,还需要进行局域网的配置工作,这样才能让处于同一局域网下的设备(如手机)连接到这台电脑及后台==。这个方法我也忘了,所以需要您和其他做PHP后台开发的同仁咨询。==如果您已经知道怎么做了,也欢迎不吝赐教,我好记录在本文章中,供更多人的来学习==。

  一些约定条件如下

  • [x] 手机客户端能成功连接后台服务器,并与后台服务器进行数据交互
  • [x] 密码为原始输入的字符串,不经过MD5等加密方式的加密(正常开发时,请务必进行加密处理)
  • [x] 传输方式选择GET传输(为了安全起见,最好使用POST传输方式)
  • [x] 登录账号只选择手机号(正常开发时,登录的账号可能还有email或者用户名)

二、数据库和表的创建及初始化

  使用SQLyog或者phpMyAdmin创建一个名为testAppDatabase的数据库,“基字符集”选择“utf8”,“数据库排序规则”选择“utf8_general_ci”,如下图所示(图像截取的是使用SQLyog软件创建数据库的情况,使用phpMyAdmin类似):
使用SQLyog创建新数据库.PNG

  然后,在testAppDatabase数据库下,新建一个名为userInformationTable的表,“引擎”选择“InnoDB”,“字符集”选择“utf8”,“核对”选择“utf8_general_ci”,最后创建列名及每一列对应的数据类型以及是否可以为空等,并设置userID为主键、正数、自增,如下图所示(图像截取的是使用SQLyog软件创建表的情况,使用phpMyAdmin类似):
使用SQLyog创建新表.PNG

  正常情况下,每一列都最好设置为“非空”,如果用户没有输入,那么可以默认使用“N/A”等填充,等用户输入了当前列对应的内容了,再替换掉“N/A”即可。

  因为我们是做登录模块的验证,没有经过注册,因此,数据库中是没有信息的。我们可以手动先填写一些信息,供测试使用。填写好的内容如下图所示(使用的phpMyAdmin客户端插入的数据)
插入数据.PNG

  ==注意,此时的密码是完全的明文密码,未进行任何加密,这主要是为了测试方便使用,正常开发时,请务必将保存到数据库中的密码进行加密处理。==

  至此,数据库相关的“配置”就处理完了,下面是php代码相关的内容。

三、php代码

  在php代码中,我们主要完成的是接收客户端传输过来的数据,并将数据与数据库进行匹配验证,一般验证的内容有两点:

  • [x] 用户输入的账号是否存在
  • [x] 用户输入的账号存在的情况下,账号和密码是否与数据库中的一一匹配

  因此,我们的php代码主要就是围绕这两个逻辑来编写。

  1. 首先,编写数据库连接代码,并保存到其它用户读取不到的位置。

  对php有一些了解的人应该知道,保存在htddoc路径(对于使用WAMP集成的环境来说,就是www文件夹下,如下图)下的文件,是可以被浏览器通过输入网址的方式读取到的,如果将登录数据库使用的账户和密码信息放到这个文件夹下,那么数据库是非常不安全的。
www目录.png

  因此,我们通常将连接数据库需要的php代码单独编写并保存为“.php”格式的文件,然后将这个文件放置在与“www”同级的位置,如下图所示的“connectionToDB.php”文件。
连接数据库文件存放位置.PNG

  使用php编辑器编辑“connectionToDB.php”文件,写入的代码如下:

connectionToDB.php

<?php$dbc = mysqli_connect('192.168.1.101', 'root', '你设置的登录数据库的密码', 'testAppDatabase') or die("连接失败:".mysql_error());  //连接数据库的格式通常为//$dbc = mysqli_connect(hostname, 登录账号, 登录密码, 数据库的名称) or die("连接失败:".mysql_error());  //hostname:一般是localhost,也常设置为作为后台的电脑的IP地址,查询的方法是“运行->cmd->ipconfig /all”,在控制台中找到IPv4地址。//对于局域网,这个IP地址可能会不断的变化,因此,如果没有做IP固化的操作,每次使用后台服务器时,最好都加纳差一下这个IP地址,然后将“connectionToDB.php”中的IP地址换为正在使用的地址//登录账号:一般是根用户root。如果不使用根用户,就使用数据库拥有者为你开辟的用户名和密码//登录密码:对应登录账号的密码//数据库名称:要连接的数据库的名称。一般一个产品只有一个数据库,该数据库中有很多的表  
?>

  ==注意:php代码的编写,一定要使用utf-8的编码格式,这点要切记。下面提到的php文件均采用这种编码格式,将不再赘述。==

  1. 接着,编写和登录验证相关的php代码,将其保存为“login.php”文件并保存到www目录下,如下图所示:

登录的php文件路径.png

  “www”目录就想到于在浏览器中输入的localhost或者192.168.1.101这个IP地址,所以能看到,我们要编写的“login.php”在下两级目录下,知道这点这对于我们编写“login.php”文件中的某些代码是有必要的。

login.php

<?phpheader('Content-type:text/html;charset=utf-8');  //代码的方式设置编码方式require_once('../../../connectionToDB.php');  //一个"../"代表一级目录,//因为我们的“connectionToDB.php”文件与“www”文件夹在同一级目录下//从“login.php”追溯“connectionToDB.php”需要进过三级目录,所以需要三个"../"$postedData = $_REQUEST;  //$_REQUEST既可以获取到通过POST方式传输的数据,也可以获取到通过GET方式传输的数据//获取用户输入的账号的形式:手机号、邮箱地址还是一般用户名$userAccountType = $postedData['Account_Type'];//获取用户输入的账号和密码  $userAccount = $postedData['User_Account'];$userPassword = $postedData['User_Password'];//根据账户形式获取对应的账号内容,用于后面的比对//是否账号是否存在的标签以及是否登录成功的标签$accountBeingOrNotFlag = "0";  //0代表账号不存在,1代表账号存在$loginOKOrNotFlag = "0";  //0代表登录失败,1代表登录成功switch ($userAccountType) {case "Telephone":  //账号是手机号$q = "SELECT * FROM userinformationtable WHERE UserTelephoneNumber = $userAccount";  //查询数据库有没有这个手机号$r = @mysqli_query($dbc, $q);$rows = @mysqli_num_rows($r);  //查询到的信息的行数,如果行数不是0,说明查询到了信息if($rows) {//行数不是0,说明有这个手机号,设置标签的值为1$accountBeingOrNotFlag = "1";  //账号存在//查询账号和密码是否匹配$qA = "SELECT * FROM userinformationtable WHERE UserTelephoneNumber = '$userAccount' and UserPassword = '$userPassword'";$rA = @mysqli_query($dbc, $qA);$rowsA = @mysqli_num_rows($rA);if($rowsA) {//行数不是0,说明账号和密码匹配,设置标签值为1,登录成功$loginOKOrNotFlag = "1";  }else {//行数是0,说明账号和密码不匹配,设置标签值为0,登录失败$loginOKOrNotFlag = "0";  }}else {//行数是0,说明账号不存在,设置标签值为0$accountBeingOrNotFlag = "0";  }//将标签值保存到数组中,然后将其传递给客户端,客户端根据标签值判断对应的操作逻辑$returnArr = array("accountBeingOrNotFlag" => $accountBeingOrNotFlag, "loginOKOrNotFlag" => $loginOKOrNotFlag);//下面的两行代码是方便测试使用,即将我们测试的一些内容保存到一个.log文件中,然后通过查看这个文件,看结果是否是我们想要的$dccc = print_r($returnArr, true);file_put_contents('C://Users/Administrator/Desktop/zj.log', $dccc);//关闭数据库连接mysqli_close($dbc);//将要传递给客户端的结果信息通过json编码的形式输出echo json_encode($returnArr);  break;//下面的代码注释和上面的这个case里面的类似,不再赘述case "EmailAddress":$q = "SELECT * FROM userinformationtable WHERE UserEmailAddress = $userAccount";$r = @mysqli_query($dbc, $q);@$rows = mysql_num_rows($r);if($rows) {$accountBeingOrNotFlag = "1";  //账号存在$qA = "SELECT * FROM userinformationtable WHERE UserEmailAddress = '$userAccount' and UserPassword = '$userPassword'";//$qA = "SELECT * FROM userinformationtable WHERE UserTelephoneNumber = 13240132824 and UserPassword = l19880226";$rA = @mysqli_query($dbc, $qA);$rowsA = @mysqli_num_rows($rA);if($rowsA) {$loginOKOrNotFlag = "1";  //登录成功}else {$loginOKOrNotFlag = "0";  //登录失败}}else {$accountBeingOrNotFlag = "0";  //账号不存在}$returnArr = array("accountBeingOrNotFlag" => $accountBeingOrNotFlag, "loginOKOrNotFlag" => $loginOKOrNotFlag);mysqli_close($dbc);echo json_encode($returnArr);  //输出json格式break;case "NormalName":$q = "SELECT * FROM userinformationtable WHERE UserNormalName = $userAccount";$r = @mysqli_query($dbc, $q);@$rows = mysql_num_rows($r);if($rows) {$accountBeingOrNotFlag = "1";  //账号存在$qA = "SELECT * FROM userinformationtable WHERE UserNormalName = '$userAccount' and UserPassword = '$userPassword'";$rA = @mysqli_query($dbc, $qA);$rowsA = @mysqli_num_rows($rA);if($rowsA) {$loginOKOrNotFlag = "1";  //登录成功                }else {$loginOKOrNotFlag = "0";  //登录失败}}else {$accountBeingOrNotFlag = "0";  //账号不存在}$returnArr = array("accountBeingOrNotFlag" => $accountBeingOrNotFlag, "loginOKOrNotFlag" => $loginOKOrNotFlag);mysqli_close($dbc);echo json_encode($returnArr);  //输出json格式break;}?>

  好了,和登录有关的php代码已经编写完成了,下面就开始编写iOS客户端的代码。

四、iOS客户端

  iOS客户端的代码,我们将采用MVC的架构来编写。

  可能有人会问,只是一个demo,为什么不将M也合并到V中一起写呢?这个就和我在文章开头提到的坑有关了。

  我们先来看一个将MVC写在一个viewController中的例子

  1. 将MVC写在一个viewController中的例子

  我们随便新建一个基于单视图的工程,然后在ViewController.m文件中编写如下代码:

ViewController.m的viewDidLoad方法中

- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.NSURL *url = [NSURL URLWithString:@"http://192.168.1.101/testApp/Login/login.php"];NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];//设置请求方式 POSTrequest.HTTPMethod = @"POST";//设置请求的超时时间request.timeoutInterval = 60;request.HTTPBody = [[NSString stringWithFormat:@"User_Account=%@&User_Password=%@&Account_Type=%@",@"13542138562",@"testApp123456", @"Telephone"] dataUsingEncoding:NSUTF8StringEncoding];NSURLSession *session = [NSURLSession sharedSession];//4 创建网络任务 NSURLSessionTask//通过网络会话 来创建数据任务NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSLog(@"网络请求完成");NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSLog(@"data = %@", data);NSLog(@"result = %@", result);_str = result;NSLog(@"1.2_str = %@", _str);//        dispatch_async(dispatch_get_main_queue(), ^{
//
//            // do something
//
//
//            _str = result;
//
//            NSLog(@"1.2_str = %@", _str);
//
//
//        });}];//5 发起网络任务[dataTask resume];NSLog(@"_str = %@", _str);
}

  这段代码本来是想完成的工作是:将登陆的信息传递给后台之后,后台进行验证,并将验证的结果(没有账号、账号密码不匹配、账号密码匹配)传回给客户端,然后由客户端根据返回回来的标签值做响应的操作。但是运行这段代码之后,通过断点调试,会发现,dataTaskWithRequest:completionHandler:并没有按照顺序执行,而是直接跳过,然后执行了[dataTask resume];方法,接着就是NSLog函数输出_str的值,会发现值是空的。当viewDidLoad代码块全部执行完毕后(即执行到最后一个右大括号}),才会执行dataTaskWithRequest:completionHandler:代码块中的内容。虽然此后会更新_str的值,但此时其实客户端已经接收了第一次的_str的值了,如果不做其它的工作,我们是很难得到想要的结果了。

  后来经过多次的调试、验证,最终才发现,使用通知可以解决这个问题。这也就是为啥我要把M单独写的原因:我们可以在M里面发送通知,然后在view里面注册通知和实现通知的方法。

  我们分别创建一个继承于NSObject的RegisterAndLoginModel文件,一个继承于UIViewController的LoginViewController文件,以及一个继承于UIView的LoginView文件。

  1. 编写RegisterAndLoginModel文件

RegisterAndLoginModel.h

#import <Foundation/Foundation.h>@interface RegisterAndLoginModel : NSObject- (void)checkTheUserAccount : (NSString*)userAccount andPassword : (NSString*)userPassword withAccountType : (NSString*)accountType;@end

RegisterAndLoginModel.m

#import "RegisterAndLoginModel.h"@implementation RegisterAndLoginModel//GET方式提交数据
- (void)checkTheUserAccount : (NSString*)userAccount andPassword : (NSString*)userPassword withAccountType : (NSString*)accountType {NSMutableDictionary *returnDictionary = [[NSMutableDictionary alloc]initWithCapacity:2];NSLog(@"userAccount = %@, userPassword = %@, accountType = %@", userAccount, userPassword, accountType);//1.构造URL网络地址NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://192.168.1.101/testApp/Login/login.php?User_Account=%@&User_Password=%@&Account_Type=%@",userAccount,userPassword, accountType]];//2.构造网络请求对象  NSURLRequestNSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];NSLog(@"request = %@", url);//3.设置请求方式 GETrequest.HTTPMethod = @"GET";//设置请求的超时时间request.timeoutInterval = 60;NSURLSession *session = [NSURLSession sharedSession];//4 创建网络任务 NSURLSessionTask。通过网络会话 来创建数据任务NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSLog(@"网络请求完成");NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];NSLog(@"接收到的数据为%@",jsonDic);[returnDictionary setObject:jsonDic forKey:@"returnDictionaryKey"];[[NSNotificationCenter defaultCenter] postNotificationName:@"loginStatusInformationDictionary" object:returnDictionary];}];//5.发起网络任务[dataTask resume];
}
  1. 编写LoginViewController文件

LoginViewController.h

#import <UIKit/UIKit.h>
#import "LoginView.h"
#import "RegisterAndLoginModel.h"@protocol LoginViewControllerDelegate <NSObject>@optional- (void)goToRegisterViewController;- (void)loginSucceed;@end@interface LoginViewController : UIViewController<LoginViewDelegate>
{NSString *accountTypeString;
}@property (assign, nonatomic) id<LoginViewControllerDelegate>loginViewControllerDelegate;
@property (strong, nonatomic) RegisterAndLoginModel *registerAndLoginModel;
@property (strong, nonatomic) LoginView *loginView;@end

LoginViewController.m

#import "LoginViewController.h"@interface LoginViewController ()@end@implementation LoginViewControllerint accountIsNotNULL = 0;  //账号是否为空
int loginPasswordIsOK = 0;  //密码格式是否正确
int loginBtnPressedNumbers = 0;  //登录按钮累计点击次数- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.//添加通知,监测后台服务器返回的标签值[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getTheLoginStatusDiecitonary:) name:@"loginStatusInformationDictionary" object:nil];_loginView = [[LoginView alloc]initTheLoginViewWithFrame:CGRectMake(0, 0, deviceScreenWidth, deviceScreenHeight)];_loginView.loginViewDelegate = self;[_loginView.goToRegisterButton addTarget:self action:@selector(goToRegisterButtonPressed:) forControlEvents:UIControlEventTouchUpInside];[_loginView.findPasswordButton addTarget:self action:@selector(findPasswordButtonPressed:) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:_loginView];_registerAndLoginModel = [[RegisterAndLoginModel alloc]init];}- (void)loginButtonPressed : (UIButton*)sender {NSLog(@"点击了登录");NSLog(@"loginBtnPressedNumbers = %i", loginBtnPressedNumbers);//首先判断用户输入的账号的类型if(![self checkPhoneNumInputWithString:_loginView.loginAccountTextField.text]) {//不是手机号if(![self isEmailAddress:_loginView.loginAccountTextField.text]) {//也不是邮箱地址accountTypeString = @"NormalName";}else {//是邮箱地址accountTypeString = @"EmailAddress";}}else {//是手机号accountTypeString = @"Telephone";}[_registerAndLoginModel checkTheUserAccount:_loginView.loginAccountTextField.text andPassword:_loginView.loginPasswordTextField.text withAccountType:accountTypeString];loginBtnPressedNumbers += 1;}- (void)goToRegisterButtonPressed : (UIButton*)sender {NSLog(@"去注册");[_loginViewControllerDelegate goToRegisterViewController];}- (void)findPasswordButtonPressed : (UIButton*)sender {NSLog(@"找回密码");
}#pragma mark - 实现LoginViewDelegate中的方法- (void)getTheInputStringInLoginViewFromTheTextField : (NSString*)inputString withTextFieldTag : (NSInteger)tag {if(tag == 20001) {if (inputString.length > 0) {accountIsNotNULL = 1;}else {accountIsNotNULL = 0;}}else {if((inputString.length >= 8) && (inputString.length <= 20)) {loginPasswordIsOK = 1;}else {loginPasswordIsOK = 0;}}if(accountIsNotNULL == 1 && loginPasswordIsOK == 1) {[_loginView.loginButton addTarget:self action:@selector(loginButtonPressed:) forControlEvents:UIControlEventTouchUpInside];_loginView.loginButton.alpha = 1.0;[_loginView.loginButton setBackgroundColor:[UIColor redColor]];[_loginView.loginButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];[_loginView.loginButton setUserInteractionEnabled:YES];}else {[_loginView.loginButton setBackgroundColor:[UIColor colorWithRed:211/255.0 green:211/255.0 blue:211/255.0 alpha:1.0]];[_loginView.loginButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];[_loginView.loginButton setUserInteractionEnabled:NO];}}#pragma mark - 使用正则表达式判断手机号格式是否正确-(BOOL)checkPhoneNumInputWithString : (NSString*)telephoneString {NSString * MOBILE = @"^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$";NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d)\\d{7}$";NSString * CU = @"^1(3[0-2]|5[256]|8[56])\\d{8}$";NSString * CT = @"^1((33|53|8[09])[0-9]|349)\\d{7}$";// 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];BOOL res1 = [regextestmobile evaluateWithObject:telephoneString];BOOL res2 = [regextestcm evaluateWithObject:telephoneString];BOOL res3 = [regextestcu evaluateWithObject:telephoneString];BOOL res4 = [regextestct evaluateWithObject:telephoneString];if (res1 || res2 || res3 || res4 ) {return YES;}else {return NO;}
}#pragma mark - 正则表达式判断邮箱格式是否正确- (BOOL)isEmailAddress:(NSString*)inputEmailAddress
{NSString* emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";NSPredicate* emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];return [emailTest evaluateWithObject:inputEmailAddress];}#pragma mark 实现通知方法- (void)getTheLoginStatusDiecitonary :(NSNotification*) notification {NSMutableDictionary *resultDictionary = [notification object];NSLog(@"resultDictionary = %@", resultDictionary);NSDictionary *judgmentDictionary = [resultDictionary objectForKey:@"returnDictionaryKey"];NSLog(@"judgmentDictionary = %@", judgmentDictionary);if([[judgmentDictionary objectForKey:@"accountBeingOrNotFlag"] isEqualToString:@"0"]) {//账号不存在,提示用户是否去注册NSLog(@"对不起,账号不存在");//此处的操作一定要回到主线程操作,否则程序会崩溃,警告框弹不出来dispatch_async(dispatch_get_main_queue(), ^{// do somethingUIAlertController *accountNotBeingAlert = [UIAlertController alertControllerWithTitle:@"账号不存在" message:@"对不起,您输入的账号不存在,是否前去注册?" preferredStyle:UIAlertControllerStyleAlert];UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];UIAlertAction *goToRegisterAction = [UIAlertAction actionWithTitle:@"去注册" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {//进入注册界面[_loginViewControllerDelegate goToRegisterViewController];}];[accountNotBeingAlert addAction:cancelAction];[accountNotBeingAlert addAction:goToRegisterAction];[self presentViewController:accountNotBeingAlert animated:YES completion:nil];});}else {//账号存在//判断账号和密码是否匹配if([[judgmentDictionary objectForKey:@"loginOKOrNotFlag"] isEqualToString:@"0"]) {//账号和密码不匹配NSLog(@"账号和密码不匹配,请重新输入");if(loginBtnPressedNumbers > 2) {if([accountTypeString isEqualToString:@"Telephone"]) {//用户输入的账号是手机号,显示获取短信验证码//短信验证码一段时间内只能获取三次,如果超过三次,那么显示图形验证码//更新界面元素的时候,也需要回到主线程,否则程序就崩溃或者界面UI更新错位dispatch_async(dispatch_get_main_queue(), ^{// do something_loginView.verificationCodeTextField.hidden = NO;_loginView.loginButton.frame = CGRectMake(20, 345, deviceScreenWidth - 40, 50);_loginView.goToRegisterButton.frame = CGRectMake(20, 405, deviceScreenWidth /2 - 20, 25);_loginView.findPasswordButton.frame = CGRectMake(deviceScreenWidth / 2, 405, deviceScreenWidth /2 - 20, 25);});}else {//账号是邮箱地址或者一般用户名,显示图形验证码}}}else {//账号和密码匹配,登录成功//登录成功后将登录状态信息保存到NSUserDefaults中,供程序调用NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];[defaults setObject:_loginView.loginAccountTextField.text forKey:@"accountStr"];[defaults setObject:_loginView.loginPasswordTextField.text forKey:@"passwordStr"];[defaults setObject:@"isLogin" forKey:@"isLoginStr"];[defaults synchronize];[_loginViewControllerDelegate loginSucceed];}}}@end
  1. 编写LoginView文件

LoginView.h

#import <UIKit/UIKit.h>@protocol LoginViewDelegate <NSObject>- (void)getTheInputStringInLoginViewFromTheTextField : (NSString*)inputString withTextFieldTag : (NSInteger)tag;@end@interface LoginView : UIView@property (assign, nonatomic) id<LoginViewDelegate>loginViewDelegate;@property (strong, nonatomic) UITextField *loginAccountTextField;
@property (strong, nonatomic) UITextField *loginPasswordTextField;
@property (strong, nonatomic) UITextField *verificationCodeTextField;@property (strong, nonatomic) UIButton *getVerificationCodeButton;@property (strong, nonatomic) UIButton *loginButton;@property (strong, nonatomic) UIButton *goToRegisterButton;@property (strong, nonatomic) UIButton *findPasswordButton;- (id)initTheLoginViewWithFrame : (CGRect)frame;@end

LoginView.m

#import "LoginView.h"#import "UIImage+CircleImageView.h"  //圆形头像@implementation LoginView- (id)initTheLoginViewWithFrame : (CGRect)frame {self = [super initWithFrame:frame];if(self) {//账号输入框_loginAccountTextField = [[UITextField alloc]initWithFrame:CGRectMake(20, 120, deviceScreenWidth - 40, 55)];[_loginAccountTextField setClearButtonMode:UITextFieldViewModeWhileEditing];_loginAccountTextField.placeholder = @"用户名/邮箱地址/手机号";_loginAccountTextField.keyboardType = UIKeyboardTypeDefault;_loginAccountTextField.borderStyle = UITextBorderStyleRoundedRect;_loginAccountTextField.tag = 20001;[self addSubview:_loginAccountTextField];UIImageView *accountTextFieldLeftImageView = [[UIImageView alloc]initWithFrame:CGRectMake(_loginAccountTextField.frame.origin.x + 30, _loginAccountTextField.frame.origin.y +5 , 45, 45)];accountTextFieldLeftImageView.image = [UIImage imageNamed:@"Account"];_loginAccountTextField.leftView = accountTextFieldLeftImageView;_loginAccountTextField.leftViewMode = UITextFieldViewModeAlways;//密码输入框_loginPasswordTextField = [[UITextField alloc]initWithFrame:CGRectMake(20, 190, deviceScreenWidth - 40, 55)];[_loginPasswordTextField setClearButtonMode:UITextFieldViewModeWhileEditing];_loginPasswordTextField.placeholder = @"输入8~20位字符的密码";_loginPasswordTextField.keyboardType = UIKeyboardTypeDefault;_loginPasswordTextField.borderStyle = UITextBorderStyleRoundedRect;_loginPasswordTextField.secureTextEntry = YES;_loginPasswordTextField.tag = 20002;[self addSubview:_loginPasswordTextField];UIImageView *passwordTextFieldLeftImageView = [[UIImageView alloc]initWithFrame:CGRectMake(_loginPasswordTextField.frame.origin.x + 10, _loginPasswordTextField.frame.origin.y + 5, 40, 40)];passwordTextFieldLeftImageView.image = [UIImage imageNamed:@"password"];_loginPasswordTextField.leftView = passwordTextFieldLeftImageView;_loginPasswordTextField.leftViewMode = UITextFieldViewModeAlways;//验证码输入框_verificationCodeTextField = [[UITextField alloc]initWithFrame:CGRectMake(20, 260, deviceScreenWidth - 40, 55)];[_verificationCodeTextField setClearButtonMode:UITextFieldViewModeWhileEditing];_verificationCodeTextField.placeholder = @"输入4位短信验证码";_verificationCodeTextField.keyboardType = UIKeyboardTypeDefault;_verificationCodeTextField.borderStyle = UITextBorderStyleRoundedRect;_verificationCodeTextField.tag = 20003;_verificationCodeTextField.hidden = YES;[self addSubview:_verificationCodeTextField];UIImageView *verificationCodeFieldLeftImageView = [[UIImageView alloc]initWithFrame:CGRectMake(_verificationCodeTextField.frame.origin.x + 30, _verificationCodeTextField.frame.origin.y +5 , 45, 45)];verificationCodeFieldLeftImageView.image = [UIImage imageNamed:@"Account"];_verificationCodeTextField.leftView = verificationCodeFieldLeftImageView;_verificationCodeTextField.leftViewMode = UITextFieldViewModeAlways;//登录按钮_loginButton = [UIButton buttonWithType:UIButtonTypeCustom];_loginButton.frame = CGRectMake(20, 275, deviceScreenWidth - 40, 50);_loginButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;_loginButton.titleLabel.font = [UIFont systemFontOfSize:17.0];[_loginButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];[_loginButton setTitle:NSLocalizedString(@"LoginButtonName", nil) forState:UIControlStateNormal];[_loginButton setBackgroundColor:[UIColor colorWithRed:211/255.0 green:211/255.0 blue:211/255.0 alpha:1.0]];[_loginButton setUserInteractionEnabled:NO];[self addSubview:_loginButton];//去注册按钮_goToRegisterButton = [UIButton buttonWithType:UIButtonTypeSystem];_goToRegisterButton.frame = CGRectMake(20, 335, deviceScreenWidth /2 - 20, 25);_goToRegisterButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;_goToRegisterButton.titleLabel.font = [UIFont systemFontOfSize:14.0];[_goToRegisterButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];[_goToRegisterButton setTitle:NSLocalizedString(@"GoToRegisterButtonName", nil) forState:UIControlStateNormal];[_goToRegisterButton setBackgroundColor:[UIColor clearColor]];[self addSubview:_goToRegisterButton];//找回密码按钮_findPasswordButton = [UIButton buttonWithType:UIButtonTypeSystem];_findPasswordButton.frame = CGRectMake(deviceScreenWidth / 2, 335, deviceScreenWidth /2 - 20, 25);_findPasswordButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;_findPasswordButton.titleLabel.font = [UIFont systemFontOfSize:14.0];[_findPasswordButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];[_findPasswordButton setTitle:NSLocalizedString(@"GetPasswordButtonName", nil) forState:UIControlStateNormal];[_findPasswordButton setBackgroundColor:[UIColor clearColor]];[self addSubview:_findPasswordButton];//添加通知,监测输入内容[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginAccountTextFieldTextDidChangeNotification:) name:UITextFieldTextDidChangeNotification object:_loginAccountTextField];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginPasswordTextFieldTextDidChangeNotification:) name:UITextFieldTextDidChangeNotification object:_loginPasswordTextField];}return self;}#pragma mark - 实现通知的方法- (void)loginAccountTextFieldTextDidChangeNotification:(NSNotification *)notification {UITextField *textField = notification.object;[self.loginViewDelegate getTheInputStringInLoginViewFromTheTextField:textField.text withTextFieldTag : textField.tag];}- (void)loginPasswordTextFieldTextDidChangeNotification:(NSNotification *)notification {UITextField *textField = notification.object;[self.loginViewDelegate getTheInputStringInLoginViewFromTheTextField:textField.text withTextFieldTag : textField.tag];}@end

五、一些会碰到的错误

  1. [UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread

  这个问题说的是需要在主线程来完成这个工作,碰到这个问题的地方是这个示例中,如果用户输入的账户不存在,弹出来一个警告框提示用户是否要去注册的时候,如果警告框的相关代码没有在主线程中操作的话,就会有这个问题。

  1. Main Thread Checker: UI API called on a background thread: -[UIView setHidden:]

  这个提示是说部分UI的更新需要在主线程中完成,如果没有在主线程中完成这个操作,可能会有错位界面。

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 如何设计一款APP的登录模块

    &emsp;&emsp;登录,是用户深入了解一个产品的敲门砖。简洁的登录模式,让用户能拥有一个非常良好的体验。因此,在设计登录模块时,要尽量简化流程,减少用户输入,提升整个环节的流畅度。 一、登录模块需要考虑的因素 &emsp;&emsp;通常登录模块需要考虑的因素…...

    2024/4/19 19:49:23
  2. 休闲网络游戏设计

    1、棋类游戏设计棋类游戏的主要代表作有:军棋、中国象棋、围棋。(一)游戏介绍这3种游戏在中国可以说是源远流长,中国象棋、围棋的参与人数是2人,而军棋可以2人或者4人一起玩。军棋:一种拥有广泛群众基础的常见棋,同样是通过以大吃小及杀死关键子的规则进行游戏。本来这种…...

    2024/4/17 22:05:50
  3. Android GridView 特殊属性

    1.android:numColumns=”auto_fit” //GridView的列数设置为自动2.android:columnWidth=”90dp " //每列的宽度,也就是Item的宽度3.android:stretchMode=”columnWidth" //缩放与列宽大小同步4.android:verticalSpacing=”10dp” //两行之间的边…...

    2024/4/5 1:10:53
  4. 面试考点——用户态和内核态的区别

    在计算机系统中,通常运行着两类程序:系统程序和应用程序,为了保证系统程序不被应用程序有意或无意地破坏,为计算机设置了两种状态:系统态(也称为管态或核心态),操作系统在系统态运行——运行操作系统程序用户态(也称为目态),应用程序只能在用户态运行——运行用户程序 在…...

    2024/5/2 23:51:40
  5. MyBatis sqlMap 的解析过程

    MyBatis sqlMap 的解析过程未完待续…………………………………………...

    2024/4/12 19:50:46
  6. 从相册读取本地保存的二维码并跳转h5链接

    因公司业务需求,在扫描二维码基础的前提下,也需要满足用户点击相册按妞,从相册获取本地保存二维码实现签到功能,在网上查阅相关资料后,整理了下,有以下几种方式:ios8.0以后可以通过使用系统原生的框架实现该功能,即CIDetector,直接上代码,但是通过验证发现,大部分二维码都能够识…...

    2024/4/5 1:10:50
  7. 牛博威:成熟的反外挂系统一般企业未必能承受

    腾讯科技讯 3月18日消息,在今日举行的腾讯网络安全技术峰会上,游戏安全和反外挂方面的专家牛博威表示,反外挂系统并非越成熟越好,成熟的反外挂系统会让一般公司很难承受,大大增加了运营成本。同时,越是成熟出名的反外挂系统越被人研究得多,反而增加了被攻破的几率。 牛…...

    2024/4/12 19:51:06
  8. 如何设计一款AndroidAPP

    开发工具的选择开发工具首选Android studio ,其作为Google官方指定的Android开发工具,其发展已经有了很长一段时间,目前已经成为了Android特定的开发工具。2.App设计风格 这一点对于一个开发者来说,貌似没有决定权,最终的决定权在产品部门手里。尽管这样,我还是会尽力说服…...

    2024/4/9 8:20:36
  9. 多线程面试题(值得收藏)

    史上最强多线程面试47题(含答案),建议收藏 金九银十快到了,即将进入找工作的高峰期,最新整理的最全多线程并发面试47题和答案总结,希望对想进BAT的同学有帮助,由于篇幅较长,建议收藏后细看~ 1、并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且…...

    2024/5/2 23:06:53
  10. 大有可为,SuperTextView(v3.2.1)

    Hi,开发者,来见识一下全新的 SuperTextView 吧!...

    2024/5/2 23:40:23
  11. QT开发和MFC开发的经典案例

     大家来欣赏下Qt写的程序(摘自百度百科) 3DSlicer, a free open source software for visualization and medical image computing AcetoneISO:镜像文件挂载软件 Adobe Photoshop Album,一个图像组织应用程序 [35] Arora:一款跨平台的开源网页浏览器 Autodesk MotionBu…...

    2024/4/18 0:16:14
  12. python 和 sqlmap的安装使用

    由于sqlmap是基于python2.5开发的,所以若要使用sqlmap,请安全python2.5以下版本,废话不多收了: 第一步:安装python2.5并添加path路径方法/步骤1现在python官网上下载和自己本机匹配的python版本,看好自己的机器是64为的还是32位的2下载好了python安装包后双击python安装包…...

    2024/4/17 2:17:23
  13. C++面试题汇总 (一)

    C++面试题汇总 (一)一,基础题二,算法题 一,基础题new、delete、malloc、free关系 delete会调用对象的析构函数,和new对应free只会释放内存,new调用构造函数。malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非…...

    2024/4/19 12:12:48
  14. 申请Apple ID

    申请AppleID需要邮箱地址,提交时候的不能一下多申请code,否则会限制下一步的申请成功。申请之后登录developer.apple.com,在首页下面 进developer program去enroll,申请开发者帐号,申请企业开发者帐号需要用到公司邓白氏编码,若公司未申请过,需要在苹果网站上填写公司信…...

    2024/4/18 18:19:43
  15. sqlmap的应用实战

    今天有幸在kali中文网上查看了很多大神写的sqlmap的教程,其中还在大神的文章里找到了一个悲催的网站www.bible-history.com/,所以就按照前人总结,给这个悲催的网站脱裤了。。。。下面详细的讲一下怎么给网站脱裤,啊,不,是拖库。。。。。 1.首先要知道可以注入的网址是什么…...

    2024/4/12 19:51:01
  16. 你必须学会的OkHttp,带你快速上车

    引子OkHttp 知名第三方网络框架SDK,使用简单,性能优秀,但是内核并不简单,此系列文章,专挑硬核知识点详细讲解. 何为硬核,就是要想深入研究,你绝对绕不过去的知识点正文大纲OkHttp是什么? OkHttp怎么用? OkHttp源码核心类之一:分发器详解 OkHttp源码核心类之一:拦截器…...

    2024/4/19 0:58:56
  17. 国内一线互联网公司内部面试题库

    欢迎在GitHub或者CSDN上关注我GitHub: https://github.com/JackyAndroidCSDN: http://blog.csdn.net/rain_butterfly国内一线互联网公司内部面试题库在线阅读地址面试题来自于百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐内部题库熟悉本文中列出的知识点会大大增加通过前…...

    2024/4/13 9:38:12
  18. Git安装步骤

    1.Git下载链接http://git-scm.com/downloads2.下载后得到git-2.10.0-intel-universal-mavericks.dmg 双击打开后,双击apk开始安装3.终端查看git安装版本 git --version4.创建一个全球用户名 git config --global user.name "FIRST_NAME LAST_NAME"5.创建一个全…...

    2024/4/5 1:11:00
  19. 安装sqlmap+python正确姿势

    简单说一下,SQLMap是利用Python语言写的,所以需要将Python这个语言环境给安装上。具体SQLMap的功能就不在这里介绍了,只介绍安装过程;工具/原料Win7或者win8系统Python2.7.9SQLMap方法/步骤1首先百度下载Python:这里最新的版本为2.7.9,并且根据自己电脑是32位还是64位,下…...

    2024/4/12 19:51:06
  20. Git使用命令

    Git使用1.git init初始化;2.git status 查看状态; 3.git add <name> ;4.git commit -m5.git remote add <name> <url>;git push <name>6.git push --set-upstream origin master如果当前分支控制没有上游分支时,用这个命令7.git push --set-upstream…...

    2024/4/12 19:52:07

最新文章

  1. 基于 Wireshark 分析 IP 协议

    一、IP 协议 IP&#xff08;Internet Protocol&#xff09;协议是一种网络层协议&#xff0c;它用于在计算机网络中实现数据包的传输和路由。 IP协议的主要功能有&#xff1a; 1. 数据报格式&#xff1a;IP协议将待传输的数据分割成一个个数据包&#xff0c;每个数据包包含有…...

    2024/5/3 6:13:36
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 文件输入/输出流(I/O)

    文章目录 前言一、文件输入\输出流是什么&#xff1f;二、使用方法 1.FileInputStream与FileOutputStream类2.FileReader与FileWriter类总结 前言 对于文章I/O(输入/输出流的概述)&#xff0c;有了下文。这篇文章将具体详细展述如何向磁盘文件中输入数据&#xff0c;或者读取磁…...

    2024/4/30 2:44:51
  4. 理解 Golang 变量在内存分配中的规则

    为什么有些变量在堆中分配、有些却在栈中分配&#xff1f; 我们先看来栈和堆的特点&#xff1a; 简单总结就是&#xff1a; 栈&#xff1a;函数局部变量&#xff0c;小数据 堆&#xff1a;大的局部变量&#xff0c;函数内部产生逃逸的变量&#xff0c;动态分配的数据&#x…...

    2024/5/1 13:25:19
  5. Jmeter02-1:参数化组件CVS

    目录 1、Jmeter组件&#xff1a;参数化概述 1.1 是什么&#xff1f; 1.2 为什么&#xff1f; 1.3 怎么用&#xff1f; 2、Jmeter组件&#xff1a;参数化实现之CSV Data Set Config(重点中重点) 2.1 是什么&#xff1f; 2.2 为什么&#xff1f; 2.3 怎么用&#xff1f; …...

    2024/5/1 13:53:24
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/2 16:16:39
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/2 9:28:15
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57