iOS 初步開發完問題小記

題外話

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

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

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

正題

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

首頁.png
個人中心.png

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

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

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    //監聽鍵盤出現和消失,解決鍵盤遮擋最后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 鍵盤出現
-(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那邊負責顯示邀請人數和獎勵金額
  • js調用本地,查看邀請記錄 標識處理
  • js調用本地,調用本地友盟分享
邀請好友頁面.png

核心代碼(相應代碼位置自己調一下)如下:

#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. 上傳頭像

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

上傳圖片.png

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

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

最好自己用的地方如下設置:
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) {
        //設置頭像
        [self alterHeadPortrait];
    }
}

- (void)alterHeadPortrait{
    //解決iOS8在調用系統相機拍照時,會有一兩秒的停頓,然后再彈出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:通過相冊(呈現全部相冊),UIImagePickerControllerSourceTypePhotoLibrary
        //獲取方式2,通過相機,UIImagePickerControllerSourceTypeCamera
        //獲取方法3,通過相冊(呈現全部圖片),UIImagePickerControllerSourceTypeSavedPhotosAlbum
        PickerImage.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        //允許編輯,即放大裁剪
        PickerImage.allowsEditing = YES;
        //自代理
        PickerImage.delegate = self;
        //頁面跳轉
        [self presentViewController:PickerImage animated:YES completion:nil];
    }]];
    //按鈕:拍照,類型:UIAlertActionStyleDefault
    [alert addAction:[UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
        /**
         其實和從相冊選擇一樣,只是獲取方式不同,前面是通過相冊,而現在,我們要通過相機的方式
         */
        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;
    //上傳頭像到服務器
    [self reqUpdateHeader:newPhoto];
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark
#pragma mark 上傳頭像到服務器
- (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();
        //設置工廠的緩沖區的大小,當上傳的文件大小超過緩沖區的大小時,就會生成一個臨時文件存放到指定的臨時目錄當中。
        factory.setSizeThreshold(1024*100);//設置緩沖區的大小為100KB,如果不指定,那么緩沖區的大小默認是10KB
        //創建一個文件上傳解析器
        ServletFileUpload upload = new ServletFileUpload(factory);
         //解決上傳文件名的中文亂碼
        upload.setHeaderEncoding("UTF-8"); 
        //設置上傳單個文件的大小的最大值,目前是設置為1024*1024字節,也就是1MB
        upload.setFileSizeMax(1024*1024);
        //設置上傳文件總量的最大值,最大值=同時上傳的多個文件的大小的最大值的和,目前設置為10MB
//        upload.setSizeMax(1024*1024*10);
        //4、使用ServletFileUpload解析器解析上傳數據,解析結果返回的是一個List<FileItem>集合,每一個FileItem對應一個Form表單的輸入項
        List<FileItem> list = upload.parseRequest(request);

4. label自動換行問題

網上查挺多的,這里只是記錄下,以后好查閱??

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

5. label設置部分字體顏色

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

UILabel *lb = [[UILabel alloc]initWithFrame:CGRectMake(ContentX, 0, kScreenWidth-ContentX, kRowHeight+10)];
        lb.textColor = [UIColor grayColor];
        NSString *str1 = @"密碼為6-15個字符,建議字母數字和特殊字符混合,登錄密碼必須和交易密碼不同。新用戶交易密碼為登錄密碼。";
        NSMutableAttributedString *str = [[NSMutableAttributedString alloc]
                                          initWithString:str1];
        //    //設置字號
        //    [str addAttribute:NSFontAttributeName value:font range:range];
        //設置文字顏色
        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. 動態獲取cell高度

待寫

7. 重寫導航左側返回按鈕

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

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

    self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
    //設置文字前景色
    [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. 程序延遲執行

場景:操作完之后,例如修改密碼完成之后,先toast,之后延時3秒再進行頁面跳轉。若不延時,toast顯示是看不到的。
網上后來看到有三種方式,大概為: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

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

產品頁.png

核心代碼如下:

//轉到產品列表頁
- (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. 充值(調用第三方寶付接口)

充值接口目前這個版本走的其實都是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) {
                //跳轉到第三方寶付充值
                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(@"返回的參數是:%@",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:@"支付結果:%@",params] delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
    }
}

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

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容

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