iOS總結2

 runLoop 定時器(NSTimer, CADisplayLink)需要加入runLoop,注意不用時需要銷燬,因爲是addTarget傳入selfself又對定時器強引用。開發中只有這一個地方會用到runLoop


c語言中沒有對象,c語言中對象其實就是結構體


RAC接管了蘋果的所有事件機制(addTarget,代理,通知,KVO,時鐘,網絡的異步回調),在信號內部通過3個方法sendNexterrorcompleted,訂閱者只需要監聽不同的代碼塊就可以接收到對應的信息,冷信號熱信號,信號一點有訂閱者就會執行信號裏面的代碼

解耦了,只需要訂閱就能獲取信息

信號組,是用來同時監聽多個事件,reduce參數可以返回想要的數值,比如兩個文本框都有內容時返回真,這時next打印是1,來控制按鈕等的狀態,在這裏再做相應的登錄操作

自學方法,使用每個控件時,先到頭文件看看有什麼方法

UI和模型之間的雙向綁定,UI到模型只需要監聽UI的屬性變化,即使用信號,模型到UIRAC(nameTextField, text) = RACObserve(self.person, name); RAC(ageTextField, text) = [RACObserve(self.person, age) map:];類型轉換用map


使用顏色不能帶alpha透明度,控件的父控件有背景顏色,如果使用alpha需要判斷父子控件疊加的面積大小和疊加後的顏色,影響性能


項目中儘量實現右滑pop到上一層的功能,人性化


終端停止podCtrl+C


SDWebImage沒有網絡指示器功能,需要自己手動添加;AFNetworking(在完成啓動的方法中,但是再次運行會閃一下。如果圖片太大的話就不會緩存,而且使用的是系統緩存)和YYWebImage(在setImageWithUrl方法中直接設置optional)有網絡指示器功能

SDWebImage使用靜態圖片完全沒問題,但如果使用動態gif圖片,佔用內存過多


[self.navigationController setNavigationBarHidden:NO animated:YES];導航條的顯示和隱藏


中途改變了狀態欄的顏色,需要使用[self.navigationController setNeedsStatusBarAppearanceUpdate];進行重繪


UI儘量不適用第三方框架


POP第三方,主要看POPAnimatableProperty.hiOS開發必備


字典轉模型就是工廠方法


單元測試主要是邊界測試(邏輯測試),是測試暴露在.h的方法,不包含UI測試,MVVM適合單元測試,因爲所有的邏輯代碼都沒有在控制器,不用進入某個頁面來測試

性能耗時測試:CACurrentMediaTime和單元測試

單元測試包括:常規測試,性能測試,異步測試

UI測試:以前是instrument,現在可以用Xcode自帶的UIText功能。猴子測試:使用instrument



KVC可以給只讀屬性賦值


表格性能問題:兩幀刷新之間運算沒有做完(減少計算量)。測試時一定要用真機測試(內存、cpu和電腦差別很大)。柵格化,將cell中所有內容生成一張獨立圖片,在滾動過程中只顯示圖片,如微信。cell.layer.shouldRasterize = YES; cell.layer.rasterizationScale = [UIScreen mianScreen].scale; 如果cell比較複雜,可以使用異步繪製(慎用) cell .layer.drawsAsynchronously = YES; 不要動態創建子視圖,所有的子視圖都需要設置背景顏色,並且不能帶alpha


關於購物車:將數據源的每一條數據存成一個獨立的字典,key爲行號,value爲選中狀態,並將這些字典存入一個數組中。不論是去做一個購物軟件,或是其他軟件,有購物車或者類似於購物車的頁面都是很常見的。

常見的購物車一般可分存本地和存服務器。存在哪裏對於我們客戶端的開發其實差別不大。

以存儲在本地爲例,我們可以使用數據庫來做,如果數據結構並不複雜,也可以使用NSUserDefaults來存儲一個數組,但切記不要傳入空。

我們以這樣子簡單的界面效果爲例:



每一行左邊有一個按鈕可以來選擇,也可以進行全選操作。

我們可以吧每一行的按鈕用一個自定義的UIButton來佈局,可以給這個button添加一個屬性用來記錄他所在的行號。

爲了簡化操作,我們給全選按鈕添加監聽,來區分選中狀態和默認狀態,就像這樣。



viewdidload中加入這樣的代碼:

[objc] view plain copy

[_allChooseButton addObserver:self forKeyPath:@"buttonState" options:NSKeyValueObservingOptionNew context:@"_allChooseButtonStateChange"];


並實現它的回調方法:

[objc] view plain copy

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(voidvoid *)context {

    if (context ==@"_allChooseButtonStateChange") {

        if (_allChooseButton.buttonState == ButtonStateNormal) {

            [_allChooseButton setBackgroundImage:[UIImage imageNamed:@"goods_n"] forState:UIControlStateNormal];

        }else {

            [_allChooseButton setBackgroundImage:[UIImage imageNamed:@"goods_s"] forState:UIControlStateNormal];

        }

    }

}


接下來,我們需要完成選中,未選中,全選,等狀態的判斷和存儲。

我們可以準備一個全局的可變數組並初始化,用來存儲所有數據每一個的選中狀態。

[objc] view plain copy

_allCellStateArray = [[NSMutableArray alloc]init];


並將我們的數據每一個對象的選中狀態存入數組,或者說每一行的狀態,我們讓他默認不被選中:

[objc] view plain copy

for (int i =0; i < _resultValue.count; i ++) {

    NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];

    [dic setValue:@"0" forKey:[NSString stringWithFormat:@"%ld",(long)i]];

    [_allCellStateArray addObject:dic];

}

存入的字典的key爲當前的行號,value爲選中狀態,我們用1表示被選中,0表示未被選中。

當我們點擊全選按鈕時,按鈕的圖片會發生變化,並且選中狀態也會發生變化,先在cellforrow方法中加入代碼:

[objc] view plain copy

cell.chooseButton.indexNumber = indexPath.row;

if ([[[_allCellStateArray objectAtIndex:indexPath.row] objectForKey:[NSString stringWithFormat:@"%ld",(long)indexPath.row]] intValue]==0) {

    // value0時,按鈕的狀態爲不選中

    cell.chooseButton.buttonState = ButtonStateNormal;

}else {

    cell.chooseButton.buttonState = ButtonStateClicked;

}

if (cell.chooseButton.buttonState == ButtonStateNormal) {

    // 當狀態爲不選中時

    [cell.chooseButton setBackgroundImage:[UIImage imageNamed:@"goods_n"] forState:UIControlStateNormal];

}else {

    // 當狀態爲選中時

    [cell.chooseButton setBackgroundImage:[UIImage imageNamed:@"goods_s"] forState:UIControlStateNormal];

}

[cell.chooseButton addTarget:self action:@selector(cellChooseClick:) forControlEvents:UIControlEventTouchUpInside];



上面兩段代碼可以寫到一個if語句中。

當我們點擊按鈕時,我們要改變按鈕的狀態,並且要將存放我們狀態的數組做修改。

[objc] view plain copy

#pragma mark - 選擇

- (void)cellChooseClick:(EMButton *)sender {

    if (sender.buttonState == ButtonStateNormal) {

        

        NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];

        [dic setValue:@"1" forKey:[NSString stringWithFormat:@"%ld",(long)sender.indexNumber]];

        [_allCellStateArray replaceObjectAtIndex:sender.indexNumber withObject:dic];

        BOOL isAll =YES;

        for (int i =0; i < _allCellStateArray.count; i ++) {

            int a = [[[_allCellStateArray objectAtIndex:i] objectForKey:[NSString stringWithFormat:@"%d",i]] intValue];

            if (a ==0) {

                isAll = 0;

            }

        }

        if (isAll) {

            

            

            _allChooseButton.buttonState = ButtonStateClicked;

        }

        

    }else {

        

        

        

        _allChooseButton.buttonState = ButtonStateNormal;

        

        NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];

        [dic setValue:@"0" forKey:[NSString stringWithFormat:@"%ld",(long)sender.indexNumber]];

        [_allCellStateArray replaceObjectAtIndex:sender.indexNumber withObject:dic];

    }

    NSIndexPath *indexPath=[NSIndexPath indexPathForRow:sender.indexNumber inSection:0];

    [self.mainTable reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath,nil] withRowAnimation:UITableViewRowAnimationMiddle];

}


中間的bool判斷是用來實現:當用戶在未全選狀態下,選擇了所有行,全選按鈕變爲全選狀態;當用戶點擊了全選按鈕進入全選狀態,後又將其中一行取消選擇,則全選狀態取消。如圖:



至此,所有的選擇取消邏輯就完成了,不管是點擊了提交按鈕來獲取選擇的對象,還是在下方顯示商品數量和價格。我們都可以通過保存每行數據狀態的數組來在我們的數據源中取對象。

[objc] view plain copy

#pragma mark - 提交按鈕

- (void)submitMethod:(EMButton *)sender {

    

    NSMutableArray *array = [[NSMutableArray alloc]init];

    for (int i =0; i < _allCellStateArray.count; i ++) {

        if ([[[_allCellStateArray objectAtIndex:i] objectForKey:[NSString stringWithFormat:@"%d",i]] intValue]==1) {

            [array addObject:[_resultValue objectAtIndex:i]];

        }

    }

    NSLog(@"submit:%@   %ld",array,(long)array.count);

    

}


用來改變下方的商品數量的方法:

[objc] view plain copy

- (void)changeInfoLabel {

    NSMutableArray *array = [[NSMutableArray alloc]init];

    for (int i =0; i < _allCellStateArray.count; i ++) {

        if ([[[_allCellStateArray objectAtIndex:i] objectForKey:[NSString stringWithFormat:@"%d",i]] intValue]==1) {

            [array addObject:[_resultValue objectAtIndex:i]];

        }

    }

    

    _countNumber = (int)array.count;

    _money = 0;

    for (int i =0;i < array.count; i ++) {

        _money += [[[array objectAtIndex:i] objectForKey:@"buyNum"] intValue];

    }

    _tabInfoLabel.text = [NSString stringWithFormat:@"%d件商品,%d",_countNumber,_money];

    NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:_tabInfoLabel.text];

    UIColor * color1 =   [UIColor colorWithRed:214.0/255.0 green:74.0/255.0 blue:115.0/255.0 alpha:1.0] ;

    [str addAttribute:NSForegroundColorAttributeName value:color1 range:NSMakeRange(1,[NSString stringWithFormat:@"%d",_countNumber].length)];

    [str addAttribute:NSForegroundColorAttributeName value:color1 range:NSMakeRange(1+[NSString stringWithFormat:@"%d",_countNumber].length+5,[NSString stringWithFormat:@"%d",_money].length)];

    

    [str addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"Helvetica" size:16.0] range:NSMakeRange(1,2)];

    

    _tabInfoLabel.attributedText = str;

}


我們可以在全選按鈕的方法,單選按鈕的方法中調用此方法,這樣在我們每次點擊的時候,都能時刻改變下方的數量價格信息。

我們的購物車基本上就寫好啦。

如果想加入加減某個商品的數量,或者刪除某個商品的功能,如:



那我們就需要多加一些判斷了,比如加減按鈕,並不會影響到我們存放每行選中狀態的數組,這個改變的是數據源,我們需要實時的改變我們原來在本地存儲的數據源(也可以在退出購物車頁面的時候統一存儲,但如果用戶在此頁面時退出程序,便無法存儲新修改的數據)。

刪除功能需要我們修改數據文件的同時,也不要忘記同時需要修改狀態數組。這樣子,我們的購物車又多了兩個新功能。

如果你的購物車數據是從服務器下載的,道理和存本地一樣,只是我們不能時時修改數據文件,這裏我們最好還是在離開此頁面時同意修改,否則會很費流量。


最後,總結一下最核心的部分:將數據源的每一條數據存成一個獨立的字典,key爲行號,value爲選中狀態,並將這些字典存入一個數組中。


關於socket

①服務端創建一個ServerSocket對象,指定端口號,ServerSocket對象等待客戶端的連接請求。

②客戶端創建一個Socket對象,指定主機地址和端口號,向服務端發出連接請求。

③服務端接收到客戶端的連接請求,建立一條TCP連接,再創建一個Socket對象與客戶端的Socket對象進行通信。

④服務端和客戶端分別創建字節輸入流和字節輸出流,通過字節輸入流獲得對方發來的數據,通過字節輸出流向對方發送數據。

⑤當一方決定結束通信時,向對方發送結束信息;另一方接收到結束信息後,雙方分別關閉各自的TCP連接。

ServerSocket對象停止等待客戶端的連接請求。


1. 使用長鏈接減少請求,這個有框架來這着忘記叫什麼了。

2.使用Hybird混合開發這個有個框架WebJavascriptBridge可以用還有Reactnative

3.Hotfix JSPatch Android Andfix(或dexposed

4.後臺業務主系統與移動App之間建立一個網關係統。這個比較困難,需要重新建立一個後端研發組開發網關係統接收與相應App請求,同時調用業務系統處理請求,網關的意義在於1.快速響應由於後端變動導致的數據異常造成App Crash2.優化與App之間的網絡請求。3.建立App使用情況信息收集


儘量使圖片大小和UIImageView大小相同,縮放圖片很耗性能


由於 CADisplayLink 綁定的方法會在每次屏幕刷新時被調用,精確度相當之高。正是基於這個特點,CADisplayLink非常適合 UI 的重繪


逆向開發:主要目的是在不能輕易獲得必要的生產信息的情況下,直接從成品分析,推導出產品的設計原理。作用:開發週期短,成本低。可以研究和學習其他app的技術




關於父類子類繼承關係

.繼承:

子類可以直接複用父類中的成員.子類繼承父類所有方法的聲明和實現非私有的實例變量以及協議 繼承時要在.h中聲明一下繼承具有單根性和傳遞性

繼承的根類:大多都繼承自 NSObject 類,所以在定義一個類時,要繼承NSObject 類。


繼承就是代碼優化公共部分交給父類


例如:


Person是父類WorkerWorker都繼承了Person成爲子類)(注:oc中的所有類都繼承與NSObject


#import "Person.h"

@interface Worker : Person


@end


#import "Person.h"

@interface Worker : Person

@end


.繼承的特點:

使用繼承可以實現代碼的複用,減少代碼冗餘;

Objective-C中一個類可以繼承另一個類;

被繼承的類稱爲父類或超類(基類);

繼承的類稱爲子類或派生類;(孩子類);

子類可以直接擁有父類中所有允許子類繼承的屬性和方法;

(繼承關係是可以傳遞的)子類除了可以調用父類的方法,也可以調用父類的父類的方法,也就是說繼承可以確保某個父類型之下的所有類都會有父類型所持有的全部方法;

子類可以有自己的成員變、量屬性和方法;

(單一繼承性)Objective-C不支持多重繼承。

.繼承的作用:

繼承的標識爲英文的“:”冒號(),使用繼承可以定義一個具有父類所有功能(成員和方法)的新類,它繼承了父類的功能。


.繼承中的方法重寫:

編寫子類時,某些方法(從父類繼承過來)需要自己的代碼實現;

子類允許重寫父類的方法,在調用子類對象的重寫方法時,就會調用重寫後的方法;

父類中被子類所重寫的方法則在調用子類方法時被忽略;


.super關鍵字:

如果在子類中 需要調用父類的功能,可以藉助super關鍵字;

子類中使用super發送消息時,實際上是告訴子類調用父類的方法;

如果父類沒有定義該方法,則繼續在繼承鏈上查找,直到找到爲止;

如果查到NSobject爲止仍然未找到,則報錯;

重寫方法時經常會使用super關鍵字調用父類的方法。

.爲何要使用繼承?

將所有重複的內容合併在一起,可以使代碼有效率,簡潔,才意味着是一個成功的架構。否則,修改代碼時需要修改多處,就很容易出錯。


.繼承使用注意:


父類要寫在子類前面

OC中不允許子類中擁有和父類中相同名稱的成員變量

OC中子類可以重寫父類方法,當調用子類時優先調用子類方法

繼承造成類與類之間耦合性太強,若父類不見,則子類不能使用

父類類型的變量不能用來調用子類的方法


.繼承中方法調用的流程:

首先到子類去找,如果有該方法,就調用子類方法,如果沒有,就再到父類去找,如果父類還沒有,再到父類的父類去找,如果最後還沒有找到,程序會崩潰。



聯網檢測,除了AFNetworking包含的AFNetworkReachAbility類,還有第三方的Reachability,可以用pod集成,具體可以上網搜索一下





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章