UIImage對象是iOS中用來顯示圖像數(shù)據(jù)的高級接口。我們可以從文件,NSData,Quartz圖片對象中創(chuàng)建UIImage對象??梢哉f這個類是我們接觸頻率非常高的一個類。
UIImage的不可變性
UIImage對象是不可變的,所以一旦創(chuàng)建后,我們就不能再改變它的屬性。這也就意味著,我們只能在初始化方法中提供屬性值或依賴于圖片自身的屬性值。同樣,由于其不可變,所以在任何線程中都可以安全地使用它。
如果我們想修改UIImage對象的一些屬性,則可以使用便捷方法和自定義的參數(shù)值來創(chuàng)建圖像的一份拷貝。
另外,由于UIImage對象是不可變的,所以它沒有提供訪問底層圖片數(shù)據(jù)的方法。不過我們可以使用UIImagePNGRepresentation或UIImageJPEGRepresentation方法來獲取包含PNG或JPG格式的數(shù)據(jù)的NSData對象。如下代碼所示:
創(chuàng)建UIImage對象
對于一個UIImage對象來說,它的數(shù)據(jù)源主要有以下幾種:
文件:我們可以使用init(contentsOfFile:)方法來從指定文件中創(chuàng)建對象。
純圖片數(shù)據(jù)(NSData):如果在內(nèi)存中有圖片的原始數(shù)據(jù)(表示為NSData對象),則可以使用init(data:)來創(chuàng)建。需要注意的是這個方法會對象圖片數(shù)據(jù)做緩存。
CGImage對象:如果我們有一個CGImage對象,則可以使用init(CGImage:)或init(CGImage:scale:orientation:)創(chuàng)建UIImage對象。
CIImage對象:如果我們有一個CIImage對象,則可以使用init(CIImage:)或init(CIImage:scale:orientation:)創(chuàng)建UIImage對象。
需要注意的是,如果是從文件或者純圖片數(shù)據(jù)中創(chuàng)建UIImage對象,則要求對應(yīng)的圖片格式是系統(tǒng)支持的圖片類型。
對于Objective-C來說,UIImage對象也提供了這些初始化方法對應(yīng)的便捷類方法來創(chuàng)建對象。
內(nèi)存管理
在實際的應(yīng)用中,特別是圖片類應(yīng)用中,我們可能需要使用大量的圖片。我們都知道,圖片通常都是非常占內(nèi)存的。如果同一時間加載大量的圖片,就可能占用大量的系統(tǒng)內(nèi)存。
為此,Apple采用了一種比較巧妙的策略。在低內(nèi)存的情況下,系統(tǒng)會強制清除UIImage對象所指向的圖片數(shù)據(jù),以釋放部分內(nèi)存。注意,這種清除行為影響到的只是圖片數(shù)據(jù),而不會影響到UIImage對象本身。當我們需要繪制那些圖片數(shù)據(jù)已經(jīng)被清除的UIImage對象時,對象會自動從源文件中重新加載數(shù)據(jù)。當然,這是以時間換空間的一種策略,會導(dǎo)致一定的性能損耗。
說到這里,我們不得不提一下init(named:)方法了??梢哉f我們平時創(chuàng)建UIImage對象用得最多的應(yīng)該就是這個方法。這個方法主要是使用bundle中的文件創(chuàng)建圖片的快捷方式。關(guān)于這個方法,有幾點需要注意:
緩存:這個方法會首先去系統(tǒng)緩存中查找是否有圖片名對應(yīng)的圖片。如果有就返回緩存中的圖片;如果沒有,則該方法從磁盤或者asset catalog中加載圖片并返回,同時將圖片緩存到系統(tǒng)中。緩存的圖片只有在收到內(nèi)存警告時才會釋放。因此,如果圖片的使用頻率比較低,則可以考慮使用imageWithContentsOfFile:方法來加載圖片,這樣可以減少內(nèi)存資源的消耗。當然,這需要權(quán)衡考慮,畢竟讀寫磁盤也是有性能消耗的,而且現(xiàn)在的高端機內(nèi)存已經(jīng)不小了。
多分辨率圖片處理:在iOS 4.0后,該方法會根據(jù)屏幕的分辨率來查找對應(yīng)尺寸的圖片。即我們使用時,只需要寫圖片名,而不需要指定是1x, 2x還是3x圖,該方法會自己判斷。
png圖片后綴:在iOS 4.0以后,如果圖片是png格式的,則圖片文件名不需要附帶擴展名。
線程安全性:該方法在iOS 9.0之前并不是線程安全的,在二級線程中調(diào)用可能會導(dǎo)致崩潰。在iOS 9.0之后,Apple作了優(yōu)化處理,將其改為線程安全的方法。為了避免不必要的麻煩,盡量在主線程中調(diào)用這個方法。
這個方法通過一個UIEdgeInsets來指定上下左右不變形的寬度或高度。它會返回一個新的圖像。而如果圖像被拉伸,則會以平鋪的方式來處理中間的拉伸區(qū)域。
圖片大小的限制
UIImage對象使用的圖片大小盡量小于1024*1024。因為這么大的圖片消耗的內(nèi)存過大,在將其作為OpenGL中的貼圖或者是繪制到view/layer中時,可以會出現(xiàn)問題。如果僅僅是代碼層面的操作的話,則沒有這個限制。比如,將一個大于1024*1024的圖片繪制到位圖圖形上下文中以重新設(shè)定其大小。事實上,我們需要通過這種操作來改變圖片大小,以將其繪制到視圖中。
支持的圖片格式
UIImage支持的圖片格式在UIImage Class Reference中列出來了,大家可以直接參考。
需要注意的一點是RGB-565格式的BMP文件在加載時會被轉(zhuǎn)換成ARGB-1555格式。