1. 程式人生 > >iOS學習日誌

iOS學習日誌

2015.04.23

1.
學習技巧:編譯指令#inport和#include,注意兩者區別;
區別
(1). #include 可能會引起重複引用。 如:ClassA ClassB 都引用了Class C, Class D若引用 Class A 與 Class B, 就會報重複引用的錯誤。
(1.1)@class的作用:
解決迴圈引用問題,作用是僅僅告訴編譯器,某個名稱是一個類,在.h檔案中使用;
好處:不需要引入該標頭檔案,所以編譯時效率提高,因為如果很多都引用該標頭檔案,用import將降低編譯效能;
(1.2)如果需要引用該類的方法,則在.m檔案中#import該類標頭檔案;
(2) #import 避免了這個問題,它只被編譯一次。
#import <> : 引用系統標頭檔案
#import ” ” : 引用自己建立的標頭檔案,與C語言類似
參考網址

http://blog.csdn.net/oik_ios/article/details/38685077
2.
學習技巧:在介面選擇一個物件(控制元件)後,按住option並且移動滑鼠,將實時顯示物件與當前滑鼠指向的物件之間的距離

2015.04.25

1.
學習技巧:對於propertory和synthesize的理解
Objective-C語言關鍵詞,@property與@synthesize配對使用。
功能:讓編譯好器自動編寫一個與資料成員同名的方法宣告來省去讀寫方法的宣告。

如:
1、在標頭檔案中:
C程式碼
1 @property int count;
等效於在標頭檔案中宣告2個方法:
C程式碼
1 - (int)count;
2 -(void)setCount:(int)newCount;

2、實現檔案(.m)中
C程式碼
1 @synthesize count;
等效於在實現檔案(.m)中實現2個方法。
C程式碼
1 - (int)count
2 {
3 return count;
4 }
5 -(void)setCount:(int)newCount
6 {
7 count = newCount;
8 }

以上等效的函式部分由編譯器自動幫開發者填充完成,簡化了編碼輸入工作量。

格式:

宣告property的語法為:@property (引數1,引數2) 型別 名字;

如:
C程式碼
1 @property(nonatomic,retain) UIWindow *window;
//
我的個人理解是這兩個命令能夠直接幫我寫好seeter和getter函式,所以,我的自己的程式碼應該不要出現getter和setter函式;但是要注意,不要寫漏@synthesize;這樣也就能夠用.去訪問這個變數
參考網址http://justcoding.iteye.com/blog/1444548
http://www.devtalking.com/articles/you-should-to-know-property/
3.
學習技巧:對於靜態變數的理解:
在變數前面加上static就能夠定義靜態變數,而且會初始化為0,但是,要注意,如果在方法裡面定義靜態變數,那麼就要注意只能在方法裡面呼叫,方法外部無法呼叫,可參考《objecvtive程式設計第六版》147頁
區別
區域性靜態變數:屬於所有同屬同一個類的物件共同擁有,但僅侷限於定義該變數的方法內使用,若要其它方法也能夠訪問,則定義成全域性變數即可;
例項變數:屬於每個物件所擁有。

2015.04.28

1.
學習技巧:如果需要在一個label標籤顯示多行的資訊,那麼需要告知ui label需要容納更多行的內容,參考《iOS7開發完全上手》71頁;
2.
學習技巧:不小心刪除了storyboard,解決方法:
(1)到回收站中找到該檔案,右鍵放回原位
(2)在xcode中 File> add File to “appName” , 選擇剛剛恢復到目錄下的Main.Storyboard即可恢復到xcode中,
注意 stroyBoard 是在你的app目錄下的Base.lproj 目錄中。
3.
學習技巧生命週期的理解
iOS檢視控制物件生命週期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear、viewDidDisappear的區別及用途
init-初始化程式
viewDidLoad-載入檢視
viewWillAppear-UIViewController物件的檢視即將加入視窗時呼叫;
viewDidApper-UIViewController物件的檢視已經加入到視窗時呼叫;
viewWillDisappear-UIViewController物件的檢視即將消失、被覆蓋或是隱藏時呼叫;
viewDidDisappear-UIViewController物件的檢視已經消失、被覆蓋或是隱藏時呼叫;
viewVillUnload-當記憶體過低時,需要釋放一些不需要使用的檢視時,即將釋放時呼叫;
viewDidUnload-當記憶體過低,釋放一些不需要的檢視時呼叫。
參考網址http://blog.csdn.net/weasleyqi/article/details/8090373
4.
出現問題:mac os 怎麼改開啟國外網站自動跳轉 wpkg.org
解決方法:開啟 Terminal 終端 (Finder/應用程式/實用工具/) (Finder/Applications/Utilities/) 輸入 sudo nano /private/etc/hosts 之後,會彈出來一個東西,把你的電腦密碼輸入進去。按下箭頭到頁面最底部輸入
127.0.0.1 wpkg.org
127.0.0.1facebook.net
加入了之後按 Control+O 然後 ENTER/RETURN 儲存 /private/etc/hosts 最後按 Control+X 然後退出
參考網址http://www.yxad.com/sina/1383587094326179900,但是文章裡面的地址是錯誤的,要按照我寫的來;127.0.0.1
9.
學習技巧:可以根據不同的需求來設定使用者的鍵盤
點中文字框,選擇右邊的inspector,選擇Keyboard,然後就有各種各樣的鍵盤供選擇;

11.
學習技巧:在故事編輯器要設定prepareForSegue函式,
這裡寫圖片描述
這裡的identifier應該是要和相對應,
所以,
這裡寫圖片描述
這裡可以用

if([segue.identifier isEqualToString:@"EditSegue"]);

2015.04.29:

1.
學習技巧:具有兩種切換返回場景到方式,一種是利用viewWillDisappear方法,一種是新增unwind segue;

2015.04.30

2015.05.06

1.
學習技巧:按住option鍵然後再加上三個手指,可以模擬真機中的放大縮小功能;
3.
學習技巧:例項變數名稱命名以_打頭;屬性名不以下劃線打頭;(約定)
4.
學習技巧:alpha簡介
液晶顯示器是由一個個的畫素點組成的,每個畫素點都可以顯示一個由RGBA顏色空間組成的一種色值。其中的A就表示透明度alpha,UIView中alpha是一個浮點值,取值範圍0~1.0,表示從完全透明到完全不透明。選中該圖片,即可在右邊的屬性設定中設定alpha;
6.
學習技巧:複製影象檢視UIImageView的快捷鍵是command+D;
7.
學習技巧:加入圖象時1x畫素影象直接命名即可,高解析度影象命名為[email protected]即可;程式設計時只需指定低解析度影象,必要時將自動載入高解析度影象;

8.
學習技巧:對於web檢視的一些引數設定,參考《ios7應用開發經典》201頁;
10.
學習技巧:在頁面間滾動,參考《ios7應用開發經典》212頁;
11.
學習技巧:在製作滾動檢視時,不要在超過手機螢幕的情況下加東西,以免程式不正常;
12.
學習技巧:control + e移動到本行行尾;

2015.05.07.

2015.05.10

1.
出現問題:ios 程式設計總會出現 提示 thread 1 breakpoint 1.1
解決方法:在該行最左側的藍色矩形區域右鍵,選擇delete breakpoint即可。

2015.05.13

2015.05.17

1.
學習技巧:注意,主執行緒是其他執行緒最終的父執行緒,所有介面的顯示操作必須在主執行緒進行。
2.
出現問題:後臺執行緒無法更新UI介面和響應使用者點選事件
解決方法:參考ios多執行緒概述:http://www.cnblogs.com/qingche/p/3496157.html
3.
學習技巧:gcd非同步多執行緒操作,注意引入執行緒的引數型別是:dispatch_queue_t。

2015.05.18

1.
學習技巧:instancetype和id的異同
參考網址http://blog.csdn.net/kuizhang1/article/details/18048829
2.
學習技巧:[iOS]iOS AudioSession詳解 Category選擇 聽筒揚聲器切換
參考網址http://blog.csdn.net/xy5811/article/details/8563137
如果以後程式設計沒有聲音,有可能是這個原因
3.
學習技巧
iOS控制元件的Sent Events的含義
Did End on Exit :使用者點選return或者done按鈕
Editing Changed :字元增減,Cursor改變位置等
Editing Did Begin :當field得到焦點
Editing Did end :焦點離開field
Touch Cancel :一個系統的事件,取消當前區域的點選操作
Touch Down :一個區域內的touch-down事件
Touch Down Repeat :區域內重複的touch-down事件; UITouch的tapCount方法大於1
Touch Drag Enter :手指拖進入(into)區域內的事件
Touch Drag Exit :手指從區域內拖出邊界的事件
Touch Drag Inside :手指在區域內(inside)拖的事件
Touch Up Inside :一個在區域內觸發的touch-up事件
Touch Up Outside :按下在區域外結束的事件
Value Changed :一個點選拖拽或者操作一個區域,產生一系列的值。
4.github的使用:
參考網址http://blog.csdn.net/g1jun/article/details/25422953

2015.05.19

1.
出現問題
mac 下安裝wireshark首次執行時會提示There are no interfaces on which a capture can be done
解決方法:原因是wireshark沒有獲得root的執行許可權。

在終端輸入:

sudo chown $USER:admin /dev/bp*

回車OK!
2.

出現問題:今天下載了一個原始碼,有C++檔案,然後提示:

the file couldn’t be opened because you don’t have permission to view it

2015.05.21

2015.05.24

2015.05.28

1.
學習技巧:在編寫鍵盤隱藏時,需要新增一個button,將文字去掉,修改type為custom,然後點選button,選擇xcode選單editor->arrange->send to back,在程式碼中寫好hidekeyboard,然後按住control,將button拉到歸屬的viewcontroll,選擇hidekeyboard,即可;

2015.05.30

1.

學習技巧:nstime預設的scheduledTimerWithTimeInterval是隻能在主執行緒用的,如果需要在本執行緒用,需要新增:

[[NSRunLoop currentRunLoop] addTimer:self.repeatTime forMode:NSDefaultRunLoopMode];//新增timer加入到當前執行緒的runloop中,timer才能在該執行緒生效
 [[NSRunLoop currentRunLoop] run];//NSRunLoop currentRunLoop]是獲取當前runloop的意思;

2015.07.18

2015.07.22

1.
學習技巧:經常在 Xcode IDE 裡面的程式碼中看到以下程式碼指令:

#pragma mark -   //#pragma 是什麼
#pragma mark Initialization

從技術上講,以 #pragma 開頭的程式碼是一條編譯器指令,是一個特定於程式或編譯器的指令。它們不一定適用於其它編譯器或其它環境。如果編譯器不能識別該指令,則會將其忽略。

作用:它們告訴Xcode編譯器,要在編輯器窗格頂部的方法和函式彈出選單中將程式碼分隔開,如下圖所示:
一些類(尤其是一些控制器類)可能很長,方法和函式彈出選單可以便於程式碼導航。此時加入#pragma 指令對程式碼進行邏輯組織很有效果。

注意:#pragma mark – 的“-”後面不能有空格
如果你的標誌沒有出現在彈出選單中,比如沒有分隔線出現,請在Xcode選單 “Preferences..”中的 “Code Sense”選項取消選中”Sort list alphabetically”即可。#pragma mark純粹是Xcode的工具,對程式一點影響都沒有,是為了提高程式設計師閱讀程式碼的格式。
參考網址http://my.oschina.net/u/615517/blog/90282

2015.07.28

1.
學習技巧NSURLRequest NSMutableURLRequest區別
NSURLRequest 申請的request是不可變的,但是NSMutableURLRequest是可以變化的
參考網址http://blog.csdn.net/hmt20130412/article/details/24268091
2.
學習技巧:markdown使用說明:
(1)control+shift+m 代表著開或者關preview介面(在mac中);

2015.08.01

2015.08.02

1.
學習技巧:關於自動釋放池:
自動釋放池用@autoreleasepool;
參考網址http://blog.csdn.net/hherima/article/details/16355887
2.
學習技巧NSNotificationCenter
iOS 提供了一種 “同步的” 訊息通知機制,觀察者只要向訊息中心註冊, 即可接受其他物件傳送來的訊息,訊息傳送者和訊息接受者兩者可以互相一無所知,完全解耦;
參考網址http://www.cnblogs.com/xunziji/p/3257447.html

2015.08.

1.
出現問題:之前在xcode6上寫的程式碼,在Xcode7真機除錯時發現螢幕只能顯示3.5寸的;
學習技巧:參考了網路的各種教程,未能解決,但是今天解決了:
這裡寫圖片描述
將最後一行選成(Main)就可以了,之前是未選上的;
2.
學習技巧:設定iOS裝置轉向的方法:
這裡寫圖片描述
prtrait:縱向;
upside down:縱向倒轉;
landscape left:橫向朝左;
landscape right: 橫向朝右;

2015.08.17
1.
學習技巧:關於ios以及mac中版本號的常識

NS_AVAILABLE_IOS(5_0),這就告訴我們這個方法可以在iOS5.0及以後的版本中使用。如果我們在比指定版本更老的版本中呼叫這個方法,就會引起崩潰。
NS_DEPRECATED_IOS(2_0, 6_0)這個巨集中有兩個版本號。前面一個表明了這個方法被引入時的iOS版本,後面一個表明它被廢棄時的iOS版本。被廢棄並不是指這個方法就不存在了,只是意味著我們應當開始考慮將相關程式碼遷移到新的API上去了。
NS_AVAILABLE(10_8, 6_0),這裡的NS_AVAILABLE巨集告訴我們這方法分別隨Mac OS 10.8和iOS 6.0被引入。
NS_DEPRECATED(10_0, 10_6, 2_0, 4_0),這裡表示這個方法隨Mac OS 10.0和iOS 2.0被引入,在Mac OS 10.6和iOS 4.0後被廢棄。
參考網址:http://codingobjc.com/blog/2014/02/11/ni-xu-yao-zhi-dao-de-suo-you-guan-yu-ioshe-os-xyi-qi-yong-de-apide-shi-er/

2.
respondsToSelector
學習技巧:

-(BOOL) respondsToSelector: selector 用來判斷是否有以某個名字命名的方法(被封裝在一個selector的物件裡傳遞)

3.
**學習技巧:**NSNotFound的基本用法
例一:

NSString *_string = [NSStringstrinWithFormat:@"123 456"];
NSRange _range = [_stringrangeOfString:@" "];
if (_range.location != NSNotFound){
     //有空格
}else{
     //沒有空格
}

先查詢空格的位置,然後查詢到不到位置的即為-1.可以知道是否有空格

例二:

if ([videoURL rangeOfString:@"http://".location!=NSNotFound|| [videoURL rangeOFString:@"https://"].location != NSNotFound] )
{
      //網路請求格式正常
}else{
      //網路請求格式不是以http或者https開頭的     
}

NSNotFound是用來判斷這個字串是否符合網路請求格式,即以http或https開頭。NSNotFound字面理解就好。

2015.08.18

4.
出現問題
connectSuccessful原本定義的是類裡面的成員,同時也定義為block型別的,在首次使用block去更改它的值時是沒有問題的,但是如果重新生成了一次該物件,相應地類裡面的成員connectSuccessful也會重新生成,但是實際上在block裡面connectSuccessful(原變數)依然存在,所以導致block內和block外兩者值不一樣;
解決問題
首先,通過列印block內和block外該成員變數地址可以找出問題所在,接著,又查到

Block變數,被__block修飾的變數稱作Block變數。 基本型別的Block變數等效於全域性變數、或靜態變數。

2015.08.20
1.
出現問題:更新了mac系統後,發現wiresharp出現閃退現象,在Launchpad中打不開,然後在終端用超級使用者開啟,出現下列錯誤:

2015-08-20 11:44:23.212 defaults[1593:98737] 
The domain/default pair of (kCFPreferencesAnyApplication, AppleAquaColorVariant) does not exist
2015-08-20 11:44:23.224 defaults[1594:98744] 
The domain/default pair of (kCFPreferencesAnyApplication, AppleHighlightColor) does not exist
dyld: Library not loaded: /usr/X11/lib/libcairo.2.dylib
  Referenced from: /Applications/Wireshark.app/Contents/Resources/bin/wireshark-bin
  Reason: image not found

解決問題

sudo ln -s /opt/X11 /usr/X11

2015.08.25
1.
學習技巧:
用程式碼使程式轉向設定頁面:

  NSURL *url=[NSURL URLWithString:@"prefs:root=WIFI"];//轉向->"設定wifi"頁面
        [[UIApplication sharedApplication] openURL:url];

2.
學習技巧:
設定提醒框,用block的確很方便

3.
出現問題:
EXC_BAD_ACCESS:經常的原因:訪問了一塊壞得記憶體->野指標;
學習技巧: 給空指標傳送訊息並不會報錯,所以在回收記憶體的時候記得將指標p=nil(防止在後文成為野指標);養成好習慣;

4.
學習技巧: 在Xcode設定監控殭屍物件:
這裡寫圖片描述

5.
學習技巧
對於記憶體管理:
(1)對於多個物件的記憶體管理,每引用一個物件,該物件計數加1(retain),每刪除一個物件,該物件計數減1(release,並不是釋放),然後釋放由系統自動控制(當計數為0的時候自動回收);
(2)alloc和release要成對出現;沒有alloc則不需要release;
看了視訊後理解了下面這段setter程式碼,每一行都是必須的(記憶體管理,非ARC狀態)

-(void) setName:(NSString *)name{
    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}

記憶體程式碼規範:
(1)對於基本資料型別,直接複製就好,不需要管理記憶體,但是如果是物件的話,必須按照上述setter方法那樣寫才規範;
(2)對於重寫dealloc:

//do something.like [car release];
[super dealloc];

一定要最後使用,不要自己呼叫,這個是要由系統自動呼叫的。

6.
學習技巧:
非常重要:
(1)如果是property隻影響getter和setter兩個,不影響dealloc;
(2)非oc類的記得要寫assign,如果是oc類的寫retain
(3)現在都用nonatomic,不要寫atomic;

@property (nonatomic,retain) 類名 *屬性名;(id也是類名,不用*)
@property (nonatomic,assign) 基本資料型別 屬性名; 

8.
學習技巧:關於自動釋放池
(1)用法(現在的ios5.0及以後的寫法)

    @autoreleasepool {//開始代表建立了釋放池
        //do something
        //如呼叫autorelease則將該物件加入自動釋放池[result autorelease](這句話會返回物件本身);
        //是棧的結構,先進後出(對於巢狀的池子)
    }//結束代表銷燬釋放池,此時對於池子裡面的每一個物件做一次release操作

(2)
自動釋放池可以巢狀使用,原則參考以上;

autorelease好處:

不需要關心物件釋放時間,不需要關心什麼時候呼叫release;

autorelease缺點:

對於佔用記憶體較大的物件不要隨便使用autorelease,佔用記憶體較小的物件沒有太大影響;

(3)使用autorelease常用錯誤:(面試題)
(3.1)使用autorelease又使用release,這樣容易導致錯誤;
(3.2)連續呼叫多次autorelease也會導致一些錯誤;
如:

[[[person alloc] autorelease] autorelease];

(3.3)在ios程式執行過程中,會建立無數個池子,這些池子都是以棧的結構存在(先進先出);
(3.4)autorelease並不是自動釋放;
(3.5)如果沒有alloc建立的物件,通過系統自帶的方法建立的物件,如nsstring,不需要呼叫release,因為系統預設它為autorelease型別的,不需要我們關心;
準則:有alloc,才需要release;
(3.6)對於系統自帶的方法中沒有包含alloc,new,copy,說明返回的物件是autorelease型別的!

9.
學習技巧:
NSNumber:命名規則,NS是字首,是為了防止兩個類重名衝突;

11.
建立物件時不要直接使用類名,而是使用self

+(id)person
{
    return [[[self alloc]init]autorelease];
}

這裡應該和C++中多型的思想類似,就是如果在物件繼承的時候,用self就能夠完成誰建立,就返回什麼型別的物件,不需要重寫建構函式;

12.
學習技巧:
ARC的判斷準則:只要沒有強指標指向物件,就會釋放物件;
指標分兩種:
(1)強指標,預設情況下,所有的指標都是強指標;strong;
(2)弱指標,weak;
如果物件A內有屬性物件B,如果希望當指向物件B的強指標被置為nil時物件A依然保持擁有物件B的值,則使用strong,如果不希望保持,則可以使用weak;
所以weak用處就在於解決迴圈引用問題,一端用strong,一端用weak;(和非ARC一起記);

13.
學習技巧:
delloc可以重寫,但是在ARC下不需要使用[super dealloc];

14.
學習技巧:
如果工程中有些檔案需要ARC,而有些不需要,設定方法參考如下:
這裡寫圖片描述
如果反過來,則輸入

-f-objc-arc

15.
學習技巧:
關於button和textview的知識:

/**
 1> UIButton    -> UIControl -> UIView

 1.1 設定控制元件的狀態
 UIControl.h內容:
 啟用、禁用
 @property(nonatomic,getter=isEnabled) BOOL enabled;
 選中、不選中
 @property(nonatomic,getter=isSelected) BOOL selected;
 高亮或者不高亮
 @property(nonatomic,getter=isHighlighted) BOOL highlighted;

 1.2 設定控制元件內容的佈局
 垂直居中方向
 @property(nonatomic) UIControlContentVerticalAlignment contentVerticalAlignment;
 水平居中方向
 @property(nonatomic) UIControlContentHorizontalAlignment contentHorizontalAlignment;

 1.3 新增/刪除監聽方法
 - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
 - (void)removeTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

 2> UILabel     -> UIView
 3> UIImageView -> UIView
 4> UITextField -> UIControl

 *** 代理設計模式,在OC中,使用最為廣泛的一種設計模式

 1> 代理的用處是什麼?
 *  監聽那些不能通過addTarget監聽的事件!(addTarget 是UIControl.h標頭檔案的內容)
 *  主要用來負責在兩個物件之間,發生某些事件時,來傳遞訊息或者資料

 2> 代理的實現步驟
 (1)    成為(子)控制元件的代理,父親(控制器)成為兒子(文字框)的代理(按住control,將文字框連線到檢視控制器)
 (2)    遵守協議->利用智慧提示,快速編寫程式碼
 (3)    實現協議方法
 */
- (void)viewDidLoad
{
    [super viewDidLoad];

    UIButton *btn =[UIButton buttonWithType:UIButtonTypeContactAdd];
    btn.center =self.view.center;
    [self.view addSubview:btn];

    [btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)click:(UIButton *)btn
{
    NSLog(@"%S",__func__);
    [btn removeTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
}

#pragma mark - 文字框代理方法
/**
 成為代理之後要做的事情,以及如何工作

 1> 協議:預先定義的一些方法名,每個方法對應不同的事件,但是沒有具體的實現

 */
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSLog(@"%@ %@", NSStringFromRange(range), string);

    // 限制輸入的長度
    int loc = range.location;
    return (loc < 6);

//    if (loc < 6) {
//        return YES;//代表顯示在文字框內,也就是算有效狀態;
//    } else {
//        return NO;//代表不顯示在文字框內,算是失效狀態;
//    }

    // 如果返回NO,就不向文字框中新增字元
//    return YES;
}

@end

16.
關於文字框的預設輸入:
在placeholder那裡設定:
這裡寫圖片描述

17.
學習技巧:

前處理器在C/C++/Objective-C語言中提供的巨集

*   __func__%s 當前函式簽名,就是當前函式名,獲取當前方法在哪個類中呼叫;
*   __LINE__ %d 在原始碼檔案中當前所在行數
*   __FILE__ %s 當前原始碼檔案全路徑
*   __PRETTY_FUNCTION__ %s 像 __func__,但是包含了C++程式碼中的隱形型別資訊。

18.
關於文字框的參考:


@implementation HMViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.userNameText becomeFirstResponder];//一進來就顯示
}

- (IBAction)login
{
    NSLog(@"%s %@ %@", __func__, self.userNameText.text, self.pwdText.text);
}

#pragma mark 文字框代理方法
// 在文字框中按回車的處理
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    NSLog(@"%@", textField);
    // 如果游標在使用者名稱,切換到密碼
    if (textField == self.userNameText) {
        // 設定密碼框成為第一響應者
        [self.pwdText becomeFirstResponder];
    } else if (textField == self.pwdText) {
        // 輸入焦點就在密碼框中
        // 如果是密碼,直接呼叫登入方法
        [self login];

        // 關閉鍵盤
//        [self.view endEditing:YES];
        // 讓密碼文字框關閉鍵盤
//        [textField resignFirstResponder];
        [self.pwdText resignFirstResponder];//撤銷密碼框成為第一響應者,這樣就能夠讓鍵盤消失
    }

    return YES;
}


@end

2015.08.26
1.

關於UIScrollView的各種尺寸:
這裡寫圖片描述
注意,這裡的contentOffset、contentSize的原點是不包括contentInset的;

3.

#import "HMViewController.h"

@interface HMViewController ()
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (nonatomic, strong) UIImageView *imageView;

// 假設影象是從網路上獲取的
@property (nonatomic, strong) UIImage *image;

@end

@implementation HMViewController

// 影象的setter
- (void)setImage:(UIImage *)image
{
    _image = image;

    // 設定影象檢視的內容
    self.imageView.image = image;
    // 讓影象檢視根據影象自動調整大小
    [self.imageView sizeToFit];

    // 告訴scrollView內部內容的實際大小
    self.scrollView.contentSize = image.size;
}

//UIImageView相當於相框,UIImage相當於相框裡面的照片
- (UIImageView *)imageView
{
    if (_imageView == nil) {
        _imageView = [[UIImageView alloc] init];

        [self.scrollView addSubview:_imageView];
    }
    return _imageView;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 設定影象
    self.image = [UIImage imageNamed:@"minion"];//選取叫做minion的圖片,必須將圖片複製進來Images.xcassets

    // 設定邊距,scrollView距離螢幕邊緣的設定
    self.scrollView.contentInset = UIEdgeInsetsMake(20, 20, 20, 20);

    // 不顯示水平滾動標示,就是右邊的下邊提示框
    self.scrollView.showsHorizontalScrollIndicator = NO;
    // 不顯示垂直滾動標示
    self.scrollView.showsVerticalScrollIndicator = NO;

    // *** (重要)偏移位置
    self.scrollView.contentOffset = CGPointMake(0, -100);//注意是負數

    // 取消彈簧效果,內容固定,不希望出現彈簧效果時
    // 不要跟bounds屬性搞混了
    self.scrollView.bounces = YES;

    UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];//+號的button
    btn.center = self.view.center;
    [self.view addSubview:btn];//這個代表將button新增到view,隨view改變,所以和scrollView不同層次,所以scrollView動,不跟著移動
    //[self.scrollView addSubview:btn];//這個代表將button新增到scrollView,隨scrollView改變,就是scrollView移動,也跟著移動
    [btn addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
}

- (void)click
{
    // 移動大圖的偏移位置,相對於檢視的偏移位置
    CGPoint offset = self.scrollView.contentOffset;
    offset.x += 20;
    offset.y += 20;

    // 注意:設定contentOffset會忽略contentSize
    self.scrollView.contentOffset = offset;
}

@end

4.
學習技巧:
複製控制元件時按住option鍵,移動滑鼠即可,先松鼠標的手,再鬆option鍵;

5.
學習技巧:

UIScrollView的用法很簡單
將需要展示的內容新增到UIScrollView中
設定UIScrollView的contentSize屬性,告訴UIScrollView所有內容的尺寸,也就是告訴它滾動的範圍(能滾多遠,滾到哪裡是盡頭)

6.

// 系統載入了Main.storyboard後,給scrollView物件進行賦值
// setScrollView是由系統自動呼叫的,先呼叫setScrollView再呼叫viewDidLoad
//- (void)setScrollView:(UIScrollView *)scrollView
//{
    // setter方法中,第一句賦值
//    _scrollView = scrollView;
//    
//    // 設定邊距,與後面的設定有先後順序
//    self.scrollView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
//    
 //   NSLog(@"%s", __func__);
//
//    // 設定滾動檢視內容
//    // 1> 如果當前有間距,根據間距自動調整contentOffset
//    // 2> 如果沒有間距,contentOffset是(0,0)
//    CGFloat h = CGRectGetMaxY(self.lastButton.frame) + 10;
//    self.scrollView.contentSize = CGSizeMake(0, h);
//}

// 檢視載入完成之後執行
- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"%s %@", __func__, self.scrollView1);

    // 設定間距
    // 只是指定內容外側邊距,並不會根據contentSize自動調整contentOffset
//    self.scrollView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
//    // 修改contentOffset
//    self.scrollView.contentOffset = CGPointMake(0, -64);
}

7.
學習技巧:

 // 設定代理
        _scrollView.delegate = self;
        // 設定最大/最小縮放比例
        _scrollView.maximumZoomScale = 2.0;
        _scrollView.minimumZoomScale = 0.2;

實現代理:

#pragma mark - UIScrollView的代理方法
/**
 1> 設定了代理
 2> 指定了最大、最小的縮放比例

 表示ScrollView是可以縮放的

 代理方法的"返回值"實際上就是控制器告訴滾動檢視,要縮放的是UIImageView
 */
// 告訴ScrollView要縮放的檢視是誰,具體的縮放實現,是由ScrollView來完成的
// 1> scrollView要知道縮放誰
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.imageView;
}

// 2> 滾動檢視即將開始縮放,通常不需要寫
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
    NSLog(@"%s", __func__);
}

// 3> 正在縮放,通常也不需要實現
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
    //    NSLog(@"%s", __func__);
    NSLog(@"%@", NSStringFromCGAffineTransform(self.imageView.transform));//這句話應該列印了具體的縮放資訊
}

// 4> 完成縮放,通常也不需要實現
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
{
    NSLog(@"%s", __func__);
}

8.
學習技巧:
如果在soryboard中拖控制元件,則不需要alloc控制元件;
如果是自己程式碼新增,則參考如下:

- (UIScrollView *)scrollView
{
    if (_scrollView == nil) {
        _scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];

        // 設定屬性
        // 設定邊距
        _scrollView.contentInset = UIEdgeInsetsMake(20, 20, 20, 20);

        // 不顯示水平滾動標示
        _scrollView.showsHorizontalScrollIndicator = NO;
        // 不顯示垂直滾動標示
        _scrollView.showsVerticalScrollIndicator = NO;

        // *** 偏移位置
        _scrollView.contentOffset = CGPointMake(0, 0);

        // 取消彈簧效果,內容固定,不希望出現彈簧效果時
        // 不要跟bounds屬性搞混了
        _scrollView.bounces = NO;

        // 設定代理
        _scrollView.delegate = self;
        // 設定最大/最小縮放比例
        _scrollView.maximumZoomScale = 2.0;
        _scrollView.minimumZoomScale = 0.2;

        [self.view addSubview:_scrollView];
    }
    return _scrollView;
}

9.
學習技巧:
可以在Xcode檢視各種佈局效果,如下:
這裡寫圖片描述
第二個是設定顯示方向(水平或者垂直)

10.
學習技巧:
自動佈局中設定水平居中或者垂直居中:
這裡寫圖片描述

11.
學習技巧:在Xcode中如果需要改變同名的變數,可以這樣做:
將游標點在該單詞,但出現下三角形的符號的時候,點選下三角形,然後點選edit,這是就已經選中了全部同名的變數,直接修改就等於了修改全部的變數;

12.
學習技巧:

    // 計時器
    /** 
     引數說明 
     1. (NSTimeInterval)ti 時間間隔,double
     2. target:self 監聽時鐘觸發的物件
     3. selector  呼叫方法
     4. userInfo,可以是任意物件,通常傳遞nil
     5. repeats:是否重複
     */
    self.counterLabel.text = @"2";

    // scheduledTimerWithTimeInterval 方法本質上就是建立一個時鐘,
    // 新增到執行迴圈的模式是DefaultRunLoopMode
    // ----------------------------------------------
    // 1>
//    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:@"hello timer" repeats:YES];

    // ----------------------------------------------
    // 2> 與1等價
//    self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];
//    // 將timer新增到執行迴圈
//    // 模式:預設的執行迴圈模式
//    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];

    // ----------------------------------------------
    // 3>
    self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];
    // 將timer新增到執行迴圈
    // 模式:NSRunLoopCommonModes的執行迴圈模式(監聽滾動模式)
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

在iOS程式中,每一個程式都是全屏的

每個程式都以自己獨立的執行迴圈,負責監聽所有的事件!

[btn addTarget:self action:@selector(click) event:]

從程式碼上看,執行迴圈有兩種模式:

NSDefaultRunLoopMode
NSRunLoopCommonModes(滾動)

一旦發現有滾動事件,預設模式暫時不監聽
(看視訊的PPT)

13.

學習技巧: 關於tableview的簡單例項:

#import "HMViewController.h"

@interface HMViewController () <UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end

@implementation HMViewController

#pragma mark - 資料來源方法
// 如果沒有實現,預設是1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 2;
}

// 每個分組中的資料行總數
// sction:分組的編號
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        // 第0個分組
        return 5;
    } else {
        return 18;
    }
}

// 告訴表格控制元件,每一行cell單元格的細節
// indexPath
//  @property(nonatomic,readonly) NSInteger section;    分組
//  @property(nonatomic,readonly) NSInteger row;        行
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 例項化TableViewCell時,使用initWithStyle方法來進行例項化
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];

    cell.textLabel.text = [NSString stringWithFormat:@"黑馬學員 %02ld 期 - %04ld", (long)indexPath.section, (long)indexPath.row];

    return cell;
}

// 返回分組的標題要顯示的文字
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return [NSString stringWithFormat:@"黑馬 %02ld 期", (long)section];
}

//返回分組頁尾的文字
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
    if (section == 0) {
        return @"太牛叉了";
    } else {
        return @"牛叉閃閃亮";
    }
}

@end

16.
學習技巧:
代理階段性小結

表格可以顯示非常豐富的資料,為了達到這一效果,設定表格的”資料來源”
@required 必須實現的方法
@optional 可選的實現方法->不強求實現->如果實現了能得到特殊的效果,如果不實現,也不影響程式的正常執行
能夠增加控制元件的靈活度

  1. 遵守協議,預先定義好方法,不實現,具體的實現工作由代理負責
    <控制元件的名字+DataSource> 定義的與資料有關的方法
    <控制元件的名字+Delegate> 定義的與事件有關的方法,通常用來監聽控制元件事件、控制元件的。

  2. 代理方法

1> 方法名以控制元件名稱開頭(沒有類字首) -> 方便程式設計師編寫的時候,快速找到需要的協議方法
2> 第一個引數是自己 -> 意味著在協議方法中,可以直接訪問物件的屬性,或者呼叫方法

18.
學習技巧:
程式碼塊存放路徑
~/Library/Developer/Xcode/UserData/CodeSnippets
換新電腦,直接替換資料夾中的內容即可

19.
學習技巧:

#import "HMViewController.h"
#import "HMHero.h"

@interface HMViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSArray *heros;
@end

@implementation HMViewController

- (NSArray *)heros
{
    if (_heros == nil) _heros = [HMHero heros];
    return _heros;
}

/**
 UITableViewStylePlain,     // 平板的格式
 UITableViewStyleGrouped    // 分組的格式
 */
- (UITableView *)tableView
{

    if (_tableView == nil) {
        // 表格控制元件在建立時必須指定樣式,只能使用以下例項化方法,因為style為readonly的,所以只能制定一次,如果需要改變,則重新例項化一個類
        _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];

        _tableView.dataSource = self;
        _tableView.delegate = self;

        [self.view addSubview:_tableView];//新增到檢視
    }
    return _tableView;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self tableView];

    // 設定行高
    self.tableView