iOS 初步開發(fā)完問題小記

題外話

基于市場運營針對老版本H5與本地混合app(偏h5,大概只有登錄注冊找回密碼用戶那塊等是本地)無法很好的推廣,公司領(lǐng)導(dǎo)決定重新改版,統(tǒng)一用本地模式。并且要求大概20個工作日完成。所以這段時間確實很忙,主要因素有以下幾點,總體就是不確定和空白:

  • 整個項目原型不確定,不斷的開會,討論。原型斷斷續(xù)續(xù)的出來了,功能還是不確定,問領(lǐng)導(dǎo),等領(lǐng)導(dǎo)答復(fù)...
  • UI這邊也是,遲遲等領(lǐng)導(dǎo)答復(fù)。9.2號開始,真正的到9月中旬,才開始有了初步的原型和UI.
  • 后臺接口也是空白,邊調(diào)邊做。
  • 項目總的人力資源:iOS 2人(1新人),安卓2人(1新人),后臺接口1人(外援2人,負責(zé)接口的人同時負責(zé)后臺pc),UI 1人,產(chǎn)品原型 1人。

后期會陸續(xù)補充整個項目的框架,以及用到的一些第三方庫及使用,以及一些費時間點。

正題

iOS這邊整個項目進度:大概功能已開發(fā)完成,測試那邊也大概的走了一遍。解決bug中。上幾個圖,嘿嘿??

首頁.png
個人中心.png

以下就記錄下自己覺得比較重要的知識點(個人觀點哈,大咖請繞行,??)

1. tableview 多個textfield, 鍵盤遮擋問題

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    //監(jiān)聽鍵盤出現(xiàn)和消失,解決鍵盤遮擋最后textfield問題
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark 鍵盤出現(xiàn)
-(void)keyboardWillShow:(NSNotification *)note
{
    CGRect keyBoardRect=[note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    self.tableview.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64 - keyBoardRect.size.height);
}
#pragma mark 鍵盤消失
-(void)keyboardWillHide:(NSNotification *)note
{
    self.tableview.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64);
}

2. oc與js簡單交互

場景:邀請頁面加載H5,如下邀請好友頁面,思路分解:

  • oc給js傳值,js那邊負責(zé)顯示邀請人數(shù)和獎勵金額
  • js調(diào)用本地,查看邀請記錄 標(biāo)識處理
  • js調(diào)用本地,調(diào)用本地友盟分享
邀請好友頁面.png

核心代碼(相應(yīng)代碼位置自己調(diào)一下)如下:

#import <WebKit/WebKit.h>
#import <JavaScriptCore/JavaScriptCore.h>
@property (strong, nonatomic) JSContext *context;
#pragma mark - 邀請好友頁面 uiwebview代理
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    self.loadCount --;
    
    //oc call js,oc給js傳值
    self.context = [[JSContext alloc] init];
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    // 打印異常
    self.context.exceptionHandler =
    ^(JSContext *context, JSValue *exceptionValue)
    {
        context.exception = exceptionValue;
        NSLog(@"%@", exceptionValue);
    };
    
    [self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"inviteInfo('%@','%@');",
                                                          self.inviteNumber,self.inviteEarn]];
    
    __weak BannerHrefVC *weakself = self;
    self.context[@"handleShare"] =
    ^(NSString *title,NSString *text)
    {
        dispatch_async(dispatch_get_main_queue(), ^(void){
            NSLog(@"%@ %@",title,text);
            weakself.shareTitle = title;
            weakself.shareText = text;
            [weakself setupUMShare];
        });
    };
    
    self.context[@"goFriendList"] =
    ^(void)
    {
        dispatch_async(dispatch_get_main_queue(), ^(void){
            [weakself.navigationController pushViewController:[[FriendsListVC alloc]initWithTitle:@"好友列表" ] animated:NO];
        });
    };
}

3. 上傳頭像

場景:個人中心,從本地拍照或者選擇相冊里面照片上傳到服務(wù)器,并更新。特別注意content-type的設(shè)置(設(shè)置不對,會發(fā)生一系列的錯誤,最折磨人的是后臺那邊能收到圖片,但是打不開,這個時候不僅跟這個參數(shù)有關(guān),后臺那邊接收方式也有關(guān)系)如下圖:

上傳圖片.png

核心代碼如下:
iOS客戶端
AFURLResponseSerialization.h 的init里面

#pragma -mark 我這邊直接改的源文件,不建議這樣改,自己在用的地方相應(yīng)設(shè)置下就好
self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"multipart/form-data",@"text/plain", nil];

最好自己用的地方如下設(shè)置:
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
    //https
    session.securityPolicy = [self customSecurityPolicy];
    session.securityPolicy.allowInvalidCertificates = YES;
    session.responseSerializer = [AFJSONResponseSerializer serializer];
    session.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"multipart/form-data",@"text/plain", nil];
    session.requestSerializer = [AFJSONRequestSerializer serializer];
#pragma -mark
#pragma -mark tableview delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
        //設(shè)置頭像
        [self alterHeadPortrait];
    }
}

- (void)alterHeadPortrait{
    //解決iOS8在調(diào)用系統(tǒng)相機拍照時,會有一兩秒的停頓,然后再彈出UIImagePickConroller的問題
    if([[[UIDevice
          currentDevice] systemVersion] floatValue]>=8.0) {
        
        self.modalPresentationStyle=UIModalPresentationOverCurrentContext;
        
    }
    
    //初始化提示框
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    //按鈕:從相冊選擇,類型:UIAlertActionStyleDefault
    [alert addAction:[UIAlertAction actionWithTitle:@"從相冊選擇" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        //初始化UIImagePickerController
        UIImagePickerController *PickerImage = [[UIImagePickerController alloc]init];
        //獲取方式1:通過相冊(呈現(xiàn)全部相冊),UIImagePickerControllerSourceTypePhotoLibrary
        //獲取方式2,通過相機,UIImagePickerControllerSourceTypeCamera
        //獲取方法3,通過相冊(呈現(xiàn)全部圖片),UIImagePickerControllerSourceTypeSavedPhotosAlbum
        PickerImage.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        //允許編輯,即放大裁剪
        PickerImage.allowsEditing = YES;
        //自代理
        PickerImage.delegate = self;
        //頁面跳轉(zhuǎn)
        [self presentViewController:PickerImage animated:YES completion:nil];
    }]];
    //按鈕:拍照,類型:UIAlertActionStyleDefault
    [alert addAction:[UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
        /**
         其實和從相冊選擇一樣,只是獲取方式不同,前面是通過相冊,而現(xiàn)在,我們要通過相機的方式
         */
        UIImagePickerController *PickerImage = [[UIImagePickerController alloc]init];
        //獲取方式:通過相機
        PickerImage.sourceType = UIImagePickerControllerSourceTypeCamera;
        PickerImage.allowsEditing = YES;
        PickerImage.delegate = self;
        [self presentViewController:PickerImage animated:YES completion:nil];
    }]];
    //按鈕:取消,類型:UIAlertActionStyleCancel
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
    [self presentViewController:alert animated:YES completion:nil];
}

#pragma mark
#pragma mark PickerImage完成后的代理方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
    
    //定義一個newPhoto,用來存放我們選擇的圖片。
    UIImage *newPhoto = [info objectForKey:@"UIImagePickerControllerEditedImage"];
    self.ivHead.image = newPhoto;
    //上傳頭像到服務(wù)器
    [self reqUpdateHeader:newPhoto];
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark
#pragma mark 上傳頭像到服務(wù)器
- (void)reqUpdateHeader:(UIImage *)image{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    NSString *strURL =  [NSString stringWithFormat:@"http://test.helloan.cn/mobile/rest/uploadPhoto/savePhoto/1?token=%@",
                        [PersonalCenterData sharedInstance].userInfo.token];
    
    [manager POST:strURL parameters:nil
           constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
       NSData *fileData = UIImageJPEGRepresentation(image, 0.1);
       NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
       formatter.dateFormat = @"yyyyMMddHHmmss";
       NSString *str = [formatter stringFromDate:[NSDate date]];
       NSString *fileName = [NSString stringWithFormat:@"%@.jpg", str];
       [formData appendPartWithFileData:fileData name:@"fileName" fileName:fileName mimeType:@"image/jpg"];
    } progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"%@",responseObject);
        if ([[responseObject objectForKey:@"code"] isEqualToString:Response_OK]) {
            [PersonalCenterData sharedInstance].userInfo.logoUrl = [responseObject objectForKey:@"logoUrl"];
        }
        [self.view makeToast:[responseObject objectForKey:@"message"]];
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"%@",error);
    }];
}

java后臺

DiskFileItemFactory factory = new DiskFileItemFactory();
        //設(shè)置工廠的緩沖區(qū)的大小,當(dāng)上傳的文件大小超過緩沖區(qū)的大小時,就會生成一個臨時文件存放到指定的臨時目錄當(dāng)中。
        factory.setSizeThreshold(1024*100);//設(shè)置緩沖區(qū)的大小為100KB,如果不指定,那么緩沖區(qū)的大小默認(rèn)是10KB
        //創(chuàng)建一個文件上傳解析器
        ServletFileUpload upload = new ServletFileUpload(factory);
         //解決上傳文件名的中文亂碼
        upload.setHeaderEncoding("UTF-8"); 
        //設(shè)置上傳單個文件的大小的最大值,目前是設(shè)置為1024*1024字節(jié),也就是1MB
        upload.setFileSizeMax(1024*1024);
        //設(shè)置上傳文件總量的最大值,最大值=同時上傳的多個文件的大小的最大值的和,目前設(shè)置為10MB
//        upload.setSizeMax(1024*1024*10);
        //4、使用ServletFileUpload解析器解析上傳數(shù)據(jù),解析結(jié)果返回的是一個List<FileItem>集合,每一個FileItem對應(yīng)一個Form表單的輸入項
        List<FileItem> list = upload.parseRequest(request);

4. label自動換行問題

網(wǎng)上查挺多的,這里只是記錄下,以后好查閱??

    UILabel *lb = [[UILabel alloc]init];
    lb.numberOfLines = 0;
    lb.lineBreakMode = NSLineBreakByWordWrapping;

5. label設(shè)置部分字體顏色

其實可以跟上面寫在一起的,但是懶得改下面的序列號了,真的好懶啊,莫怪??

UILabel *lb = [[UILabel alloc]initWithFrame:CGRectMake(ContentX, 0, kScreenWidth-ContentX, kRowHeight+10)];
        lb.textColor = [UIColor grayColor];
        NSString *str1 = @"密碼為6-15個字符,建議字母數(shù)字和特殊字符混合,登錄密碼必須和交易密碼不同。新用戶交易密碼為登錄密碼。";
        NSMutableAttributedString *str = [[NSMutableAttributedString alloc]
                                          initWithString:str1];
        //    //設(shè)置字號
        //    [str addAttribute:NSFontAttributeName value:font range:range];
        //設(shè)置文字顏色
        NSRange range =[str1 rangeOfString:@"新用戶交易密碼為登錄密碼。"];
        [str addAttribute:NSForegroundColorAttributeName value:kColorHeadPerson range:range];
        lb.attributedText = str;
        lb.numberOfLines = 0;
        lb.lineBreakMode = NSLineBreakByWordWrapping;
        lb.font = kFontText;
        [head addSubview:lb];

6. 動態(tài)獲取cell高度

待寫

7. 重寫導(dǎo)航左側(cè)返回按鈕

如下代碼也對導(dǎo)航和底部tab的顯示和隱藏做了處理

#pragma -mark viewLife
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    self.automaticallyAdjustsScrollViewInsets = NO;
    
    self.navigationController.navigationBar.barTintColor = kColorHeadPerson;
    //半透明狀態(tài)
    self.navigationController.navigationBar.translucent = NO;

    self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
    //設(shè)置文字前景色
    [self.navigationController.navigationBar setTitleTextAttributes:
  @{NSFontAttributeName:[UIFont systemFontOfSize:22],
    NSForegroundColorAttributeName:[UIColor whiteColor]}];
    //重寫返回按鈕
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"back_normal"]
                                                                            style:UIBarButtonItemStylePlain
                                                                           target:self
                                                                           action:@selector(buttonBack)];
    
    self.hud = [[MBProgressHUD alloc]initWithView:self.view];
    self.hud.delegate = self;
    self.hud.mode = MBProgressHUDModeIndeterminate;
    self.hud.label.text=@"加載中,請稍后!";
    self.hud.backgroundColor =[UIColor lightGrayColor];
    [self.view addSubview:self.hud];
}

- (void)buttonBack
{
    [self.navigationController popViewControllerAnimated:NO];
}

-(void)viewWillAppear:(BOOL)animated{
    
    [super viewWillAppear:animated];
    
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    self.tabBarController.tabBar.hidden = YES;
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    self.tabBarController.tabBar.hidden = NO;
}

8. 程序延遲執(zhí)行

場景:操作完之后,例如修改密碼完成之后,先toast,之后延時3秒再進行頁面跳轉(zhuǎn)。若不延時,toast顯示是看不到的。
網(wǎng)上后來看到有三種方式,大概為:performSelector,nstimer,gcd. 我這邊用的是gcd

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                //your code
            });

9. 從普通vc到tabitem中的一個vc

場景:從實名認(rèn)證成功頁面(該頁面為從個人中心也所push的,此頁上有個去投資按鈕)回到產(chǎn)品頁(如下圖)

產(chǎn)品頁.png

核心代碼如下:

//轉(zhuǎn)到產(chǎn)品列表頁
- (void)goInvest
{
    self.tabBarController.selectedIndex = 1;
    [self.navigationController popToRootViewControllerAnimated:NO];
}

10. 列表上拉彈回問題

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableview = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
    self.tableview.dataSource = self;
    self.tableview.delegate = self;
    self.tableview.scrollEnabled = YES;
    [self.view addSubview:self.tableview];
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    self.tableview.contentSize =CGSizeMake(0, kRowHeight*5+ButtonHeight +40+10);
}

11. 充值(調(diào)用第三方寶付接口)

充值接口目前這個版本走的其實都是web,api貌似要貴好多,以后版本公司可能會改用api。多一句,web真的好慢,其實充值這么慢,無形中會流失掉一部分想投資的用戶。

#pragma -mark
#pragma -mark 充值獲取交易號
- (void)doCharge
{
    NSLog(@"doCharge");
    NSString *token = [PersonalCenterData sharedInstance].userInfo.token;
    if (!token) {
        [self.view makeToast:NoLoginMsg];
        return;
    }
    [[PersonalCenterLogicManager sharedInstance]postChargeWithToken:token amount:[self.tfAmount.text intValue] success:^(NSDictionary *dic) {
        if ([[dic objectForKey:@"code"] isEqualToString:Response_OK]) {
            NSString *tradeNo =[dic objectForKey:@"tradeNo"];
            if (tradeNo) {
                //跳轉(zhuǎn)到第三方寶付充值
                BaoFooPayController*web = [[BaoFooPayController alloc] init];
                web.PAY_TOKEN = tradeNo;
                web.delegate = self;
                [self presentViewController: web animated:YES completion:^{ }];
            }
        }
        else{
            [self.view makeToast:[dic objectForKey:@"message"]];
        }
        
    } failure:^(NSError *err) {
        [self.view makeToast:ServerError];
    }];
}

#pragma mark - BaofooDelegate
-(void)callBack:(NSString*)params
{
    NSLog(@"返回的參數(shù)是:%@",params);
    if ([params rangeOfString:@"支付成功"].location != NSNotFound) {
        //條件為真,表示字符串searchStr包含一個自字符串substr
        ChargeSuccessVC *vc = [[ChargeSuccessVC alloc]initWithTitle:@"充值成功"];
        vc.chargeAmount = self.tfAmount.text;
        vc.bankNumber = self.bankInfo.bankNumber;
        [self.navigationController pushViewController:vc animated:NO];
    }else
    {
        //條件為假,表示不包含要檢查的字符串
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:[NSString stringWithFormat:@"支付結(jié)果:%@",params] delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
    }
}

還需待寫的有
1 銀行選擇
2 二級聯(lián)動城市選擇
3 頂部滾動等

連續(xù)上7天的班,腦殼都快炸了,回家好好休息??,看到這里的你,愿你周末愉快!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,466評論 25 708
  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,842評論 2 17
  • 巍巍雪寶頂,山下是我家; 楓葉滿山谷,煙云伴紅霞。 牧女回眸笑,午夜不成眠, 寄去相思苦,天涯手相牽。
    夏旭冬爾杰閱讀 339評論 0 3
  • “我們各自心中都有某些不愿意摒棄的東西,即使這個東西使我們痛苦得要死。我們就是這樣,就像古老的凱爾特傳說中的荊棘鳥...
    野子瘋閱讀 496評論 0 1
  • 二戰(zhàn)時的意大利,一個不知名的小島上,有個叫吉娜的女人,獨自開一爿酒吧,她是個成熟美麗的女子,已有些年紀(jì),依然風(fēng)情萬...
    桃仙君閱讀 476評論 0 1