最近看到幾篇博客是關(guān)于AutoValue的,然后自己十分喜歡物赶,一下子覺的這樣寫代碼很優(yōu)雅白指,所以決定自己也寫一篇文章介紹下AutoValue。
本文最先發(fā)表于Github酵紫,如有轉(zhuǎn)載告嘲,請注明轉(zhuǎn)載出處。
前言
首先說Android Model奖地,在開發(fā)中網(wǎng)絡(luò)請求橄唬,以及數(shù)據(jù)庫操作等,我們都會定義一個Model参歹,不同人對這個的說法不一樣仰楚,比如有Entry,Bean犬庇,Pojo僧界。
然后開發(fā)的過程中會遇到下面問題:
構(gòu)成方法:自定義構(gòu)造方法,如果實體比較復(fù)雜臭挽,可能會用到工廠模式或者是建造者模式
序列化:比如實現(xiàn)Serializable接口捂襟,Parcelable接口。
Json解析:有時候直接使用的是json數(shù)據(jù)欢峰,比如@SerializedName注解葬荷。
自定義方法:對Model的字段有setter涨共,getter方法,toString的實現(xiàn)闯狱,在處理hash的時候煞赢,需要實現(xiàn)equals和hashcode方法。
以上這么問題哄孤,其實在Eclipse和Android Studio中都是有快捷功能幫我們自動生成照筑,后面的代碼示例,就是我用Android Studio自動生成的瘦陈。
比如下面一個User類是我們的本次示例的一個Model凝危,如果按照正常的寫法,是這樣的晨逝。
publicabstractclassUserimplementsSerializable{@SerializedName("id")privateintid;@SerializedName("name")privateString name;publicintgetId() {returnid;? ? }publicvoidsetId(intid) {this.id = id;? ? }publicStringgetName() {returnname;? ? }publicvoidsetName(String name) {this.name = name;? ? }@Overridepublicbooleanequals(Object o) {if(this== o)returntrue;if(o ==null|| getClass() != o.getClass())returnfalse;? ? ? ? User user = (User) o;if(id != user.id)returnfalse;returnname !=null? name.equals(user.name) : user.name ==null;? ? }@OverridepublicinthashCode() {intresult = id;? ? ? ? result =31* result + (name !=null? name.hashCode() :0);returnresult;? ? }@OverridepublicStringtoString() {return"User{"+"id="+ id +", name='"+ name +'\''+'}';? ? }}
簡介
官方文檔給出的解釋是這樣的蛾默,大致意思是說是一個生成Java不可變的值類型工具,仔細(xì)研讀源代碼后捉貌,使用的技術(shù)是Java Apt支鸡,這個后面再做詳細(xì)解釋。
AutoValue - Immutable value-type code generation for Java 1.6+.
簡單使用
按照上面的例子趁窃,如果是AutoValue牧挣,代碼是這樣的。
首先需要在Android項目里面引入apt功能醒陆,在項目根目錄的gradle中添加瀑构,
buildscript{
repositories {
jcenter()
}dependencies{? ? ? ? classpath'com.android.tools.build:gradle:2.2.2'// 引入apt插件? ? ? ? classpath'com.neenbedankt.gradle.plugins:android-apt:1.8'}}
其次在module(一般是app目錄)中g(shù)radle使用apt插件。
apply plugin:'com.android.application'apply plugin:'com.neenbedankt.android-apt'
最后加入AutoValue依賴刨摩。
dependencies{? ? provided'com.google.auto.value:auto-value:1.3'apt'com.google.auto.value:auto-value:1.3'}
修改User類寺晌,如下所示,User已經(jīng)變成了一個抽象類澡刹,類似于使用Retrofit一樣呻征,申明已經(jīng)變成了一個接口,然后實現(xiàn)類是由AutoValue生成的代碼罢浇。
importcom.google.auto.value.AutoValue;@AutoValuepublicabstractclassUser{publicabstractintid();publicabstractStringname();publicstaticUsernewInstance(intid, String name) {returnnewAutoValue_User(id, name);? ? }}
我們可以看看AutoValue到底干了什么怕犁?
AutoValue會自動生成一個AutoValue_User栈虚,這個類是繼承了上面申明的User類担平,這個是默認(rèn)default的訪問權(quán)限,那么在其他package中是無法訪問的症副,這樣在其他代碼里面也不會看到這么奇怪的名字凌受。
同時所有的字段都是final類型阵子,如果字段是對象類型的,那么還不能為空胜蛉,這個問題先保留挠进,后面再做詳解色乾。因為申明的是final類型,那么所有的字段都是沒有setter方法的领突。
代碼里同時也實現(xiàn)了equals暖璧、hashcode、toString方法君旦。
finalclass AutoValue_User extends User {privatefinalintid;privatefinalString name;? AutoValue_User(intid,? ? ? String name) {this.id = id;if(name ==null) {thrownewNullPointerException("Null name");? ? }this.name = name;? }@Overridepublicintid() {returnid;? }@OverridepublicStringname() {returnname;? }@OverridepublicStringtoString() {return"User{"+"id="+ id +", "+"name="+ name? ? ? ? +"}";? }@Overridepublicbooleanequals(Object o) {if(o ==this) {returntrue;? ? }if(oinstanceofUser) {? ? ? User that = (User) o;return(this.id == that.id())? ? ? ? ? && (this.name.equals(that.name()));? ? }returnfalse;? }@OverridepublicinthashCode() {inth =1;? ? h *=1000003;? ? h ^=this.id;? ? h *=1000003;? ? h ^=this.name.hashCode();returnh;? }}
Immutable/Value types
剛剛上面說到澎办,所有的字段都是final類型,那么而且實現(xiàn)類也是final的金砍,有個專業(yè)術(shù)語叫Immutable局蚀。
Immutable/Value types 這個概念對有些朋友來說可能還比較陌生,簡單來說就是一個數(shù)據(jù)對象一旦構(gòu)造完成恕稠,就再也無法修改了琅绅。
這樣有什么好處呢?最大的好處就是多線程訪問可以省去很多同步控制鹅巍,因為它們是不可變的千扶,一旦構(gòu)造完成,就不會存在多線程競爭訪問問題了骆捧。多線程最麻煩的處理就是控制好讀寫問題澎羞,如果大家都是讀,那么就不存控制了凑懂,所以省去了很多同步操作。
更多關(guān)于Immutable 的介紹梧宫,可以參閱wiki接谨。
舉個Java中的例子:String和StringBuilder,String是immutable的塘匣,每次對于String對象的修改都將產(chǎn)生一個新的String對象脓豪,而原來的對象保持不變,而StringBuilder是mutable忌卤,因為每次對于它的對象的修改都作用于該對象本身扫夜,并沒有產(chǎn)生新的對象。
Immutable objects 比傳統(tǒng)的mutable對象在多線程應(yīng)用中更具有優(yōu)勢驰徊,它不僅能夠保證對象的狀態(tài)不被改變笤闯,而且還可以不使用鎖機(jī)制就能被其他線程共享。
總結(jié)下Immutable對象的優(yōu)缺點:
優(yōu)點
Immutable對象是線程安全的棍厂,可以不用被synchronize就在并發(fā)環(huán)境中共享
Immutable對象簡化了程序開發(fā)颗味,因為它無需使用額外的鎖機(jī)制就可以在線程間共享
Immutable對象提高了程序的性能,因為它減少了synchroinzed的使用
Immutable對象是可以被重復(fù)使用的牺弹,你可以將它們緩存起來重復(fù)使用浦马,就像字符串字面量和整型數(shù)字一樣时呀。你可以使用靜態(tài)工廠方法來提供類似于valueOf()這樣的方法,它可以從緩存中返回一個已經(jīng)存在的Immutable對象晶默,而不是重新創(chuàng)建一個谨娜。
缺點
Immutable也有一個缺點就是會制造大量垃圾,由于他們不能被重用而且對于它們的使用就是”用“然后”扔“磺陡,字符串就是一個典型的例子趴梢,它會創(chuàng)造很多的垃圾,給垃圾收集帶來很大的麻煩仅政。當(dāng)然這只是個極端的例子垢油,合理的使用immutable對象會創(chuàng)造很大的價值。
高級使用
Nullable
上面說過如果類中有對象類型的成員變量圆丹,那么是為非空的滩愁,但是在實際情況下,有的字段的是值就是為null辫封,所以在申明時候可申明為Nullable就可以了硝枉。
importandroid.support.annotation.Nullable;importcom.google.auto.value.AutoValue;importcom.google.gson.annotations.SerializedName;@AutoValuepublicabstractclassNullableUser{@SerializedName("id")publicabstractintid();@Nullable@SerializedName("name")publicabstractStringname();publicstaticNullableUsernewInstance(intid, String name) {returnnewAutoValue_NullableUser(id, name);? ? }}
生成代碼:
finalclass AutoValue_NullableUser extends NullableUser {privatefinalintid;privatefinalString name;? AutoValue_NullableUser(intid,@NullableString name) {this.id = id;this.name = name;? }}
測試用例
@Test(expected = NullPointerException.class)publicvoidtestUserNullPointException()throwsException {? ? ? ? User.newInstance(100,null);? ? }@TestpublicvoidtestUserNullable() {? ? ? ? NullableUser user = NullableUser.newInstance(100,"test");? ? ? ? System.out.println("user = "+ user);? ? ? ? Assert.assertEquals(user.id(),100);? ? ? ? Assert.assertEquals(user.name(),"test");? ? }
Gson序列化
Gson 使用比較麻煩,在普通的Model中倦微,只需要在字段上面添加 @SerializedName注解即可妻味。但是使用AutoValue,稍微有點繁瑣欣福。
首先需要引入一個依賴包责球,這里是Auto value gson Github。
provided'com.ryanharter.auto.value:auto-value-gson:0.4.4'apt'com.ryanharter.auto.value:auto-value-gson:0.4.4'
其次申明的抽象類中拓劝,每個方法上面添加對應(yīng)的注解雏逾,然后再添加一個typeAdapter方法,申明這個方法郑临,Gson就會根據(jù)這個找到對應(yīng)的adapter栖博,如下所示。
@AutoValuepublicabstractclassUser{@SerializedName("id")publicabstractintid();@SerializedName("name")publicabstractStringname();publicstaticUsernewInstance(intid, String name) {returnnewAutoValue_User(id, name);? ? }publicstaticTypeAdaptertypeAdapter(Gson gson) {returnnewAutoValue_User.GsonTypeAdapter(gson);? ? }}
typeAdapter方法模板如下丧叽,T就是你當(dāng)前Model的名字,寫完以后會出現(xiàn)錯誤笨触,沒事重新編譯下就好了说榆,這樣就會重新生成了代碼唱蒸。
publicstaticTypeAdaptertypeAdapter(Gson gson) {returnnewAutoValue_T.GsonTypeAdapter(gson);}
第三申明一個TypeAdapterFactory的一個實現(xiàn)類屁魏,這個類是abstract的,AutoValue也會自動生成其實現(xiàn)類。
@GsonTypeAdapterFactorypublicabstractclassMyAdapterFactoryimplementsTypeAdapterFactory{publicstaticTypeAdapterFactorycreate() {returnnewAutoValueGson_MyAdapterFactory();? ? }}
最后是單元測試宪摧,在json字符串轉(zhuǎn)Model的時候沿彭,會使用一個Gson對象睦裳,這個對象不是平常使用的對象糙箍,需要自定義配置一些東西,然后這里就用到了上面所申明的MyAdapterFactory。
@TestpublicvoidtestUserToJson() {? ? ? ? User user = User.newInstance(100,"test");? ? ? ? String json =newGson().toJson(user);? ? ? ? System.out.println(json);? ? ? ? Assert.assertEquals("{\"id\":100,\"name\":\"test\"}", json);? ? }@TestpublicvoidtestUserParseFromJson() {? ? ? ? String json ="{\"id\":100,\"name\":\"test\"}";// 自定義的Gson對象饰剥,需要配置 MyAdapterFactoryGson gson =newGsonBuilder().registerTypeAdapterFactory(MyAdapterFactory.create()).create();? ? ? ? User user = gson.fromJson(json, User.class);? ? ? ? System.out.println(user);? ? ? ? Assert.assertNotNull(user);? ? ? ? Assert.assertEquals(user.name(),"test");? ? ? ? Assert.assertEquals(user.id(),100);? ? ? ? NullableUser nullableUser = gson.fromJson(json, NullableUser.class);? ? ? ? System.out.println(nullableUser);? ? ? ? Assert.assertNotNull(nullableUser);? ? ? ? Assert.assertEquals(nullableUser.name(),"test");? ? ? ? Assert.assertEquals(nullableUser.id(),100);? ? }
Serializable & Parcelable
Serializable是Java自帶的序列化方式,和AutoValue結(jié)合不影響原先使用比规,只需要在申明的Model中實現(xiàn)Serializable接口即可。
Parcelable是Android提供的序列化方式测秸,如果需要和AutoValue結(jié)合使用,和Serializable基本差不多吧碾,實現(xiàn)相關(guān)接口,然后在Gradle文件引入相關(guān)apt依賴即可落剪。
apt'com.ryanharter.auto.value:auto-value-parcel:0.2.5'// OptionallyforTypeAdapter support? ? // compile'com.ryanharter.auto.value:auto-value-parcel-adapter:0.2.5'
上面的auto-value-parcel-adapter是可選項呢堰,是auto-value-parcel提供自定義類型轉(zhuǎn)化,相關(guān)使用可以參見Github地址凡泣。
檢查下Autovalue自動給我們實現(xiàn)的代碼枉疼,果然不出所料,全部自動生成了鞋拟。
finalclass AutoValue_User extends $AutoValue_User {publicstaticfinalParcelable.Creator CREATOR =newParcelable.Creator() {@OverridepublicAutoValue_UsercreateFromParcel(Parcel in) {returnnewAutoValue_User(? ? ? ? ? in.readInt(),? ? ? ? ? in.readString()? ? ? );? ? }@OverridepublicAutoValue_User[]newArray(intsize) {returnnewAutoValue_User[size];? ? }? };? AutoValue_User(intid, String name) {super(id, name);? }@OverridepublicvoidwriteToParcel(Parcel dest,intflags) {? ? dest.writeInt(id());? ? dest.writeString(name());? }@OverridepublicintdescribeContents() {return0;? }}
Retrofit和Rxjava結(jié)合使用
Android 開發(fā)的時候骂维,很多開發(fā)者使用Retrofit這個網(wǎng)絡(luò)庫,以及RxJava異步工具贺纲。下面舉例如何結(jié)合使用AutoValue航闺,Retrofit,Rxjava猴誊。
這里有個獲取天氣的接口潦刃,返回的結(jié)果是json,我們用這個來測試下Retrofit稠肘。
// https://api.thinkpage.cn/v3/weather/now.json?key=x4qjfuniyu97mt9y&location=beijing&language=zh-Hans&unit=c{"results": [? ? {"location": {"id":"WX4FBXXFKE4F","name":"北京","country":"CN","path":"北京,北京,中國","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now": {"text":"霾","code":"31","temperature":"10"},"last_update":"2016-12-02T14:45:00+08:00"}? ]}
申明Retrofit Api接口福铅,一個普通的調(diào)用萝毛,一個是RxJava的方式项阴。
publicinterfaceIWeatherApi{@GET("/v3/weather/now.json?key=x4qjfuniyu97mt9y&location=beijing&language=zh-Hans&unit=c")? ? Call getWeather();@GET("/v3/weather/now.json?key=x4qjfuniyu97mt9y&location=beijing&language=zh-Hans&unit=c")? ? Observable getWeatherWithRx();}
Retrofit 接口創(chuàng)建
publicclassRetrofitUtil{publicstatic TcreateApi(@NonNull Class tClass, Gson gson) {returnnewRetrofit.Builder()? ? ? ? ? ? ? ? .baseUrl("https://api.thinkpage.cn")? ? ? ? ? ? ? ? .client(newOkHttpClient.Builder().build())? ? ? ? ? ? ? ? .addConverterFactory(GsonConverterFactory.create(gson))? ? ? ? ? ? ? ? .addCallAdapterFactory(RxJavaCallAdapterFactory.create())? ? ? ? ? ? ? ? .build()? ? ? ? ? ? ? ? .create(tClass);? ? }}
Weather Model申明
publicabstractclassWeather{@SerializedName("results")publicabstractListresults();publicstaticTypeAdaptertypeAdapter(Gson gson) {returnnewAutoValue_Weather.GsonTypeAdapter(gson);? ? }}
測試用例,注意:Retrofit使用Gson和前面使用Gson使用方式一樣,需要自己自定義环揽,不然無法解決json解析問題略荡。
@TestpublicvoidtestRetrofitWithAutoValue() {? ? ? ? Gson gson =newGsonBuilder().registerTypeAdapterFactory(MyAdapterFactory.create()).create();? ? ? ? IWeatherApi weatherApi = RetrofitUtil.createApi(IWeatherApi.class, gson);try{// 同步調(diào)用Weather weather = weatherApi.getWeather().execute().body();? ? ? ? ? ? Assert.assertNotNull(weather);? ? ? ? ? ? System.out.println(weather);// Rxjava 使用weatherApi.getWeatherWithRx().subscribe(newAction1() {@Overridepublicvoidcall(Weather weather) {? ? ? ? ? ? ? ? ? ? System.out.println(weather);? ? ? ? ? ? ? ? }? ? ? ? ? ? });? ? ? ? }catch(IOException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }
運行結(jié)果,正常的返回天氣信息歉胶。
Weather{results=[ResultsItem{now=Now{code=31, temperature=9,text=霾}, lastUpdate=2016-12-02T14:15:00+08:00, location=Location{country=CN, path=北京,北京,中國, timezone=Asia/Shanghai, timezoneOffset=+08:00,name=北京,id=WX4FBXXFKE4F}}]}Weather{results=[ResultsItem{now=Now{code=31, temperature=9,text=霾}, lastUpdate=2016-12-02T14:15:00+08:00, location=Location{country=CN, path=北京,北京,中國, timezone=Asia/Shanghai, timezoneOffset=+08:00,name=北京,id=WX4FBXXFKE4F}}]}
相關(guān)插件
RoboPOJOGenerator
GsonFormat是一款A(yù)ndroid Studio的插件汛兜,它可以把json字符串,轉(zhuǎn)變成Model對象通今,很多人都喜歡用它粥谬。
但是如果使用了AutoValue,那么原先的插件就不能使用了辫塌,沒有關(guān)系漏策,本來打算自己高仿GsonFormat重新寫了一個插件,以實現(xiàn)我們的需求臼氨,后面又發(fā)現(xiàn)有一款插件可以實現(xiàn)——RoboPOJOGenerator掺喻。
RoboPOJOGenerator使用,RoboPOJOGenerator Github地址
AutoValue plugin
上面我們發(fā)現(xiàn)有了json字符串储矩,有時候還要寫factory和buildder方法感耙,那么問題來了,沒有插件能幫我們實現(xiàn)這個步驟持隧,然代碼更加的優(yōu)雅即硼,開發(fā)更加高效?
答案是肯定的屡拨,Autovalue plugin就是干這個事的谦絮。
我們用剛剛上面的Weather做演示,相關(guān)演示:
原理介紹
本文重點介紹的AutoValue只是Google Auto中的一小部分洁仗,Auto中還有其他好玩的层皱。
AutoFactory
AutoFactory和AutoValue類似,可以自動幫助代碼生成工廠類赠潦,兼容Java 依賴注入標(biāo)準(zhǔn)(JSR-330)叫胖。
代碼示例
@AutoFactorypublicclassFactoryUser{privatefinalintid;privatefinalString name;publicFactoryUser(intid, String name) {this.id = id;this.name = name;? ? }publicintgetId() {returnid;? ? }publicStringgetName() {returnname;? ? }@OverridepublicStringtoString() {return"FactoryUser{"+"id="+ id +", name='"+ name +'\''+'}';? ? }}
生成后的代碼
publicfinalclassFactoryUserFactory{@InjectpublicFactoryUserFactory() {? }publicFactoryUsercreate(intid, String name) {returnnewFactoryUser(id, name);? }}
測試代碼
@TestpublicvoidtestFactoryUser() {? ? ? ? FactoryUser user =newFactoryUserFactory().create(100,"test");? ? ? ? System.out.println(user);? ? ? ? Assert.assertNotNull(user);? ? ? ? Assert.assertEquals(100, user.getId());? ? ? ? Assert.assertEquals("test", user.getName());? ? }
AutoService
AutoService比較簡單,就是在使用Java APT的時候她奥,使用AutoService注解瓮增,可以自動生成meta信息。
AutoCommon
這個是Google對Java Apt的一個擴(kuò)展哩俭,一般的在自己寫Apt的時候绷跑,都需要繼承AbstractProcessor,但是google對它進(jìn)行了擴(kuò)展凡资,BasicAnnotationProcessor砸捏,如果你想自己寫個工具,那么就可以使用這個了。
給大家舉個栗子垦藏,Dagger當(dāng)初是Square公司受到Guice的啟發(fā)梆暖,然后自己開發(fā)出一套依賴注入框架,當(dāng)時Dagger使用的是Java反射掂骏,大家知道Java反射的效率其實并不高轰驳。
再后來都到了AutoValue的啟發(fā),在Dagger的分支上切個新分支弟灼,開發(fā)出Dagger2级解,然后這個Dagger2是由Google維護(hù)的,我們可以在Dagger2的Github上面找到證據(jù)田绑。
Auto相關(guān)使用
IntentBuilder
有時候幾個Activity之間相互跳轉(zhuǎn)的時候需要傳遞一些參數(shù)蠕趁,這些參數(shù)可以是基本類型,也有可能是復(fù)雜的類型辛馆,如果是負(fù)責(zé)的類型俺陋,必須要實現(xiàn)Serializable 或 Parcelable接口,上面也有介紹昙篙。
下面推IntentBuilder腊状,IntentBuilder也是利用代碼生成的方法實現(xiàn)的。
Activity傳參
@IntentBuilderclass DetailActivity extends Activity {@ExtraString id;@Extra@NullableString title;@OverridepublicvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);? ? ? ? DetailActivityIntentBuilder.inject(getIntent(),this);// TODO use id and title}}// 調(diào)用方式startActivity(newDetailActivityIntentBuilder("12345")? ? ? ? .title("MyTitle")? ? ? ? .build(context))
Service傳參
@IntentBuilderclass DownloadService extends IntentService {@ExtraString downloadUrl;@OverrideprotectedvoidonHandleIntent(Intent intent) {? ? ? ? MyServiceIntentBuilder.inject(intent,this);? ? }}startService(newDownloadServiceIntentBuilder("http://google.com").build(context))
FragmentArgs
上面介紹了Activity苔可、Service的傳參缴挖,但Fragment的傳參方式是不一樣的,還有需要提醒一句一般通過setter方法給Fragment傳參是不是正確的方式焚辅,必須通過setArgs的方式映屋。
相關(guān)代碼示例:
@FragmentWithArgspublicclassMyFragmentextendsFragment{@Argintid;@OverridepublicvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);? ? ? ? FragmentArgs.inject(this);// inject 之后,就可以使用 id 了}}MyFragment fragment = MyFragmentBuilder.newMyFragment(101);
其他相關(guān)
Kotlin Data Class
Kotlin 是一個基于 JVM 的新的編程語言同蜻,由 JetBrains 開發(fā)棚点。有機(jī)會可以向大家介紹這種語言。
Kotlin 中提供一種類似于AutoValue中的功能湾蔓,Data Class表示這個類似是一個數(shù)據(jù)類型瘫析。
比如下面是kotlin中對Model的寫法,就是這么的簡單默责、明了贬循、優(yōu)雅。
dataclassKotlinUser(valid:Int,valname:String)
Kotlin與Java是可以相互調(diào)用的桃序。下面是Java的測試用例杖虾。
publicclassUserTest{@TestpublicvoidtestUser() {? ? ? ? KotlinUser user =newKotlinUser(100,"test");? ? ? ? System.out.println(user);? ? ? ? Assert.assertEquals(100, user.getId());? ? ? ? Assert.assertEquals("test", user.getName());? ? }}
我們可以反編譯Kotlin生成的class字節(jié)碼,看看這個中間到底發(fā)生了什么媒熊,很明顯Kotlin做了很多的語法糖奇适,這里編譯器生成的代碼和上面Autovalue生成的代碼很像坟比。
Object-C
Object-C中可以過直接申明@property方式,然后就可以自動實現(xiàn)setter和getter方法滤愕,如果要實現(xiàn)Immutable type方式,需要注明readonly怜校。
hash间影、equals、description如果使用APPCode茄茁,代碼是可以自動生成的魂贬。
@interfaceOcUser:NSObject@property(readonly)intid;@property(retain,readonly)NSString*name;- (instancetype)initWithId:(int)idname:(NSString*)name;- (NSString*)description;- (BOOL)isEqual:(id)other;- (BOOL)isEqualToUser:(OcUser *)user;- (NSUInteger)hash;@end// ==========================#import"OcUser.h"@implementationOcUser{}- (instancetype)initWithId:(int)idname:(NSString*)name {self= [superinit];if(self) {? ? ? ? _id=id;? ? ? ? _name = name;? ? }returnself;}- (BOOL)isEqual:(id)other {if(other ==self)returnYES;if(!other || ![[other class] isEqual:[selfclass]])returnNO;return[selfisEqualToUser:other];}- (BOOL)isEqualToUser:(OcUser *)user {if(self== user)returnYES;if(user ==nil)returnNO;if(self.id!= user.id)returnNO;return!(self.name!= user.name&& ![self.nameisEqualToString:user.name]);}- (NSUInteger)hash {? ? NSUInteger hash = (NSUInteger)self.id;? ? hash = hash *31u + [self.namehash];returnhash;}- (NSString*)description {NSMutableString*description = [NSMutableStringstringWithFormat:@"<%@: ", NSStringFromClass([selfclass])];? ? [description appendFormat:@"self.id=%i",self.id];? ? [description appendFormat:@", self.name=%@",self.name];? ? [description appendString:@">"];returndescription;}@end
測試用例
#import#import"OcUser.h"intmain(intargc,constchar*argv[]) {? ? @autoreleasepool {? ? ? ? OcUser *user = [[OcUser alloc] initWithId:100name:@"test"];NSLog(@"user = %@", user);? ? }return0;}// 運行結(jié)果// user =
總結(jié)
本文主要介紹了Autovalue的主要用法,以及AutoValu周邊只是裙顽,可能說的比較多付燥,比較雜,而且有的地方也不夠深入愈犹,但是個人覺的這是一種思路键科,一種解決方案,后面如果自己需要造輪子的時候漩怎,我們是可以借鑒的勋颖。
本示例代碼地址AutoValueDemo
參考連接
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載勋锤。