1. 程式人生 > >PJBreedsViewController 元件開發總結

PJBreedsViewController 元件開發總結

這是我另外一個專案其中一個元件——品種選擇器,因為今天是週六,磨磨唧唧的造出了它。一眼看過去跟現有的通訊錄樣式和操作方式基本一致,但大家也知道我的尿性,從最開始能用三方元件就用三方到現在能自己寫就自己寫。

因為前後端都是我自己一個人在做(創業狗就是慘 = =)所以在今天萌生了很多好玩的想法,剛把這個組建弄出來後覺得有必要跟大家分享一些好玩的事情。

UI

先來看看 UI 樣式,

最開始看到設計圖時,並不認為這是一個有多少搞頭的東西,一直拖到今天。這是最終實現的成果,

思考(一)

給到我的文案是個 .docx 格式的文件,如下所示:

之前溝通過了一次,給我按照字母表順序排好就行了。最開始我的設計非常簡單,因為後端是用 python 寫的,直接從檔案中讀出資料,split

一下丟入庫裡就好了,介面直接返回 idzh_name 即可,遂開幹。

實踐(一)

# 初始化:儘量通過 python shell 呼叫該方法
def init_dog_breed():
     f = open(settings.DOG_BREED_DIR, 'r')
     f_str = f.read()
     f_str_arr = f_str.split()
     for dog_name in f_str_arr:
         dog_breed(zh_name=dog_name).save()
     f.close()
複製程式碼

從本地路徑讀取轉化成 .txt

檔案(本人對直接讀 .docx 沒把握)後簡單的操作下入庫完事,這個方法並未暴露在介面中,而且只是第一次初始化資料時需要呼叫該方法。為了方便後續產品迭代新增寵物品種資訊,做了另外一個簡單的方法:

# 新增狗品種
 def add_dog_breed(breed_name):
     dog_breed(zh_name=breed_name).save()
複製程式碼

當然,也會有貓的,因為基本上差不多就不展開了。介面上這麼寫:

@decorator.request_methon('GET')
@decorator.request_check_args(['pet_type'])
def
get_breeds(request):
pet_type = request.GET.get('pet_type', '') functions = { 'dog': dog(), 'cat': cat() } if pet_type in functions.keys(): json = { 'breeds': functions[pet_type] } return utils.SuccessResponse(json, request) else: return utils.ErrorResponse('2333', '不支援該物種', request) # 獲取所有狗品種 def dog(): dog_breeds = dog_breed.objects.all() breeds = [] for breed in dog_breeds: json = { 'id': breed.pk, 'zh_name': breed.zh_name, } breeds.append(json) return breeds 複製程式碼

猜測後續產品可能還會引入其它寵物,畢竟現代人對寵物的需求是越來越奇葩了,沒有直接 if-else ,想用 switch ,但發現 python 中並沒有 switch 語句,查閱一番資料後,發現居然可以用 key-value 完成,雖然有些稍許麻煩,但第一次見還可以把鍵值對玩成這樣!

訪問對應介面後拿到的 JSON 格式資料如下:

{
    "msgCode": 666,
    "msg": {
        "breeds": [
            {
                "id": 89,
                "zh_name": "拉布拉多尋回犬"
            },
            {·
                "id": 90,
                "zh_name": "拉薩犬"
            },
            {
                "id": 91,
                "zh_name": "臘腸犬"
            },
            {
                "id": 92,
                "zh_name": "蘭波格犬"
            },
            {
                "id": 93,
                "zh_name": "獵水獺犬"
            },
        ]
    }
}
複製程式碼

一切順利,看起來不錯,開始造客戶端 UI。客戶端上的實現同樣也是比較輕鬆,一個 tableView 的正常渲染流程即可。

資料渲染出來後,腦子已經在快速運轉,站起來活動活動,發現肚子有些餓,糾結了一會是食堂呢還是餓了麼,最後因為貧窮而選擇了食堂。

思考(二)

午飯結束後,繼續幹活。開始做資料分組,思考並發現了問題所在,如果按照上午介面所返回的資料格式去做,那麼就需要端上做資料分組,把寵物品種按照 A~Z 的順序放到一個個的 section 中,這樣不但 iOS 需要做一遍,以後 Android 也要再做一遍,而且極其有可能還是我寫,本來我就十分厭煩 Android,多花費一分鐘甚至一秒鐘都是極其不樂意的。

所有,重新思考介面返回的資料格式。可以確保的是,資料都已經按照字母序排好了,我們只需要對資料做分組,把第一個字的拼音的第一個字母相同的品種歸類為一組,最後把所有組都放到一個大的列表中,序列化為 JSON 返回即可完事。

遂又開幹!

實踐(二)

首先給品種模型新增了一個欄位 group 用於標記所屬組別,中途考慮到了不想多增遷移檔案,居然腦殘的把之前生成的表給刪了,導致後邊生成遷移檔案時對不上,最後又刪庫重來,真是多此一舉 = =。

重新把基本操作都弄完後,改造初始化資料的方法,用到了一箇中文轉拼音的庫 pinyin

# 初始化:儘量通過 python shell 呼叫該方法
def init_dog_breed():
    f = open(settings.DOG_BREED_DIR, 'r')
    f_str = f.read()
    f_str_arr = f_str.split()
    # 刪除 array 中的第一個 'A'
    del f_str_arr[0]
    group = 'A'
    for dog_name in f_str_arr:
        first_cat_name = pinyin.get(dog_name, format='strip')[0:1].upper()
        if first_cat_name != group:
            group = first_cat_name
            # 切換 group 時跳過
            continue
        dog_breed(zh_name=dog_name, group=group).save()

    f.close()
複製程式碼

這樣清洗過資料後,資料就十分清晰漂亮了:

+-----+-------+--------------------------------+
| id  | group | zh_name                        |
+-----+-------+--------------------------------+
|   1 | A     | 阿富汗獵犬                     |
|   2 | A     | 阿拉斯加雪橇犬                 |
|   3 | A     | 愛爾蘭梗                       |
|   4 | A     | 愛爾蘭紅白雪達犬               |
|   5 | A     | 愛爾蘭獵狼犬                   |
|   6 | A     | 愛爾蘭軟毛梗                   |
|   7 | A     | 愛爾蘭水獵犬                   |
|   8 | A     | 愛爾蘭峽谷梗                   |
+-----+-------+--------------------------------+
複製程式碼

而介面,只需要進行拼接同類資料即可,

# 獲取所有狗品種
def dog():
    dog_breeds = dog_breed.objects.all()
    # 所有種類
    breeds = []
    # 當前種類名
    breed_groups = []
    group = "A"
    for breed in dog_breeds:
        if breed.group != group:
            breed_group = {
                'group': group,
                'breeds': breed_groups,
            }
            breeds.append(breed_group)
            group = breed.group
            breed_groups = []
        b_group = {
            'id': breed.pk,
            'zh_name': breed.zh_name,
        }
        breed_groups.append(b_group)
    return breeds
複製程式碼

這樣,客戶端就能夠拿到已經分組好的資料:

{
    "msgCode": 666,
    "msg": {
        "breeds": [
            {
                "group": "A",
                "breeds": [
                    {
                        "group": "T",
                        "breeds": [
                            {
                                "id": 137,
                                "zh_name": "田野小獵犬"
                            }
                        ]
                    },
                ]
            },
            {
                "group": "W",
                "breeds": [
                    {
                        "id": 138,
                        "zh_name": "玩具獵狐梗"
                    },
                    {
                        "id": 139,
                        "zh_name": "玩具曼徹斯特犬"
                    },
                ]
            }
        ]
    }
}
複製程式碼

那客戶端接下來要做的事情稍微冗餘一些,但不復雜。首先先確定 tableView.sections 的值,然後返回 sectionHeaderView,接著編寫 cellForRow 渲染 cell 的方法,依然是正常的 tableView 渲染流程。

剩下的就是一些其它 UI 和互動細節上的修修補補了。

思考和總結

這次做的這個元件前後端花費的時間比例大約在 7:3,主要時間都花在客戶端上,因為是第一次做類似於這種通訊錄元件的開發,再加上是週六,讓自己的大腦和心情都放鬆了下來,沒有把時間抓得特別緊。

給我最大的收穫是最開始只考慮了後端處理資料的便利,而忘了前端處理資料的複雜,到後邊轉換了思維,用前端的思維對介面格式進行了修改,這一來一回讓自己更加明白了前後端配合是才能夠把一個東西做好,做到極致。

原文地址:PJ 的 iOS 開發之路