日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

RubyMotion 指南:API 驱动开发示例

發(fā)布時(shí)間:2025/7/14 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RubyMotion 指南:API 驱动开发示例 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

翻譯:@shiweifu
本文鏈接:http://segmentfault.com/blog/shiweifu
原文鏈接:http://rubymotion-tutorial.com/10-api-driven-example/
目標(biāo)讀者:["想了解RubyMotion開發(fā)模式", "想學(xué)習(xí)RubyMotion", "逗比"]


我們將創(chuàng)建一個(gè)使用Colr JSON API作為后端的應(yīng)用。用戶輸入顏色的16進(jìn)制值( #3B5998)他們會(huì)看見標(biāo)簽的顏色發(fā)生對(duì)應(yīng)的變化。他們可以往里添加新的顏色。

我們先考慮下程序的結(jié)構(gòu)。會(huì)有兩個(gè)Controller:一個(gè)用來(lái)搜索,一個(gè)用來(lái)顯示顏色。這兩個(gè)Controller外面都套著UINavigationController。我們還需要Model:Color、Tag,它可能并不精美,但能工作。

初始化

使用motion create Colr 命令初始化一個(gè)新的項(xiàng)目,添加bubble-wrap 到你的 Rakefile。接下來(lái)我們?cè)?/app 中創(chuàng)建兩個(gè)目錄:./app/models/ 和 ./app/controllers。

Models

首先,讓我們先看下模型。Colr API 的 Color JSON 結(jié)構(gòu)如下:

{"timestamp": 1285886579,"hex": "ff00ff","id": 3976,"tags": [{"timestamp": 1108110851,"id": 2583,"name": "fuchsia"}] }

我們的 Colors 需要timestamp,hex, id, tags這些屬性,特別注意的是,tags屬性將包含多個(gè)Tag對(duì)象

創(chuàng)建./app/models/color.rb然后填寫 Model 代碼:

class ColorPROPERTIES = [:timestamp, :hex, :id, :tags]PROPERTIES.each { |prop|attr_accessor prop}def initialize(hash = )hash.each { |key, value|if PROPERTIES.member? key.to_symself.send((key.to_s + "=").to_s, value)end}end...

PROPERTIES 這塊是個(gè)小trick,很容易就定義了屬性。需要稍微說(shuō)一下的是tags這個(gè)屬性,讓它始終返回一個(gè)Tag Model的數(shù)組。

...def tags@tags ||= []enddef tags=(tags)if tags.first.is_a? Hashtags = tags.collect |tag| Tag.new(tag) endtags.each { |tag|if not tag.is_a? Tagraise "Wrong class for attempted tag #tag.inspect"end}@tags = tagsend end

我們覆蓋了#tags 的getter和setter,所以當(dāng)tags沒有值的時(shí)候,將返回一個(gè)空的數(shù)組。#tags=保證解析和返回Tag對(duì)象數(shù)組。我們接下來(lái)編看看TagModel里面都有啥。

創(chuàng)建并打開./app/models/tag.rb,接口返回的數(shù)據(jù)如下所示:

{"timestamp": 1108110851,"id": 2583,"name": "fuchsia" }

創(chuàng)建TagModel的類,代碼短且友好:

class TagPROPERTIES = [:timestamp, :id, :name]PROPERTIES.each { |prop|attr_accessor prop}def initialize(hash = )hash.each { |key, value|if PROPERTIES.member? key.to_symself.send((key.to_s + "=").to_s, value)end}end end

Controllers

模型都已經(jīng)定義好了,你的好友「控制器君」即將上線。創(chuàng)建./app/controllers/search_controller.rb和./app/controllers/color_controller.rb 倆文件,把最基本的實(shí)現(xiàn)先寫上去:

class SearchController < UIViewControllerdef viewDidLoadsuperself.title = "Search"end end class ColorController < UIViewControllerdef viewDidLoadsuperself.title = "Color"end end

將我們的控制器帶上UINavigationController和UIWindow,甩給AppDelegate:

class AppDelegatedef application(application, didFinishLaunchingWithOptions:launchOptions)@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)@search_controller = SearchController.alloc.initWithNibName(nil, bundle:nil)@navigation_controller = UINavigationController.alloc.initWithRootViewController(@search_controller)@window.rootViewController = @navigation_controller@window.makeKeyAndVisibletrueend end

代碼堆砌完了,是時(shí)候看看成果了,執(zhí)行rake命令,在屏幕中會(huì)出現(xiàn):

一切都很好,該看看SearchController里面都有啥了。

SearchController

(譯者著:原文是系列文章,之前的部分從未出現(xiàn)過UITextField,所以這里假設(shè)UITextField從未出現(xiàn)過,不然接不上。)

我們將使用一個(gè)之前從未提到過的控件UITextField來(lái)接受用戶的輸入,當(dāng)用戶點(diǎn)擊Search按鈕時(shí)候,我們將發(fā)起一個(gè)API請(qǐng)求,這時(shí)界面不接受任何輸入,直到請(qǐng)求結(jié)束。如果請(qǐng)求成功完成,我們會(huì)push一個(gè)ColorController給用戶展示結(jié)果,否則的話會(huì)給個(gè)出錯(cuò)提示。

以下是SearchController的初始化時(shí)干活的代碼:

def viewDidLoadsuperself.title = "Search"self.view.backgroundColor = UIColor.whiteColor@text_field = UITextField.alloc.initWithFrame [[0,0], [160, 26]]@text_field.placeholder = "#abcabc"@text_field.textAlignment = UITextAlignmentCenter@text_field.autocapitalizationType = UITextAutocapitalizationTypeNone@text_field.borderStyle = UITextBorderStyleRoundedRect@text_field.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2 - 100)self.view.addSubview @text_field@search = UIButton.buttonWithType(UIButtonTypeRoundedRect)@search.setTitle("Search", forState:UIControlStateNormal)@search.setTitle("Loading", forState:UIControlStateDisabled)@search.sizeToFit@search.center = CGPointMake(self.view.frame.size.width / 2, @text_field.center.y + 40)self.view.addSubview @searchend

self.view.frame.size.height / 2 - 100設(shè)置座標(biāo)和大小的代碼是我個(gè)人習(xí)慣,設(shè)置UIControlStateDisabled是為了統(tǒng)一配置阻塞時(shí)的樣式。UITextBorderStyleRoundedRect是為了設(shè)置UITexitField的樣式,帶來(lái)更好的觀感。

rake再執(zhí)行,現(xiàn)在看到的樣子:

(譯者注:BubbleWrap是RubyMotion官方開發(fā)的一個(gè)庫(kù),里面封裝了很多用Cocoa寫起來(lái)很蛋疼的地方,使代碼更加「Ruby」)

該處理事件了。還記得我之前提到過BubbleWrap屌屌的么?使用它我們不用再像過去寫傻傻的addTarget:action:forControlEvents啥啥啥的來(lái)添加事件,代碼清晰很多:

def viewDidLoad...self.view.addSubview @search@search.when(UIControlEventTouchUpInside) do@search.enabled = false@text_field.enabled = falsehex = @text_field.text# chop off any leading #shex = hex[1..-1] if hex[0] == "#"Color.find(hex) do |color|@search.enabled = true@text_field.enabled = trueendendend

when 方法在所有UIControl的子類都可以用。使用UIControlEvent開頭的那些標(biāo)識(shí)事件位作為參數(shù)。當(dāng)請(qǐng)求發(fā)出后,我們臨時(shí)禁用UI。

(譯者注:作者的意思應(yīng)該是每個(gè)顏色都寫一段代碼去獲取,有疑問去看原文吧,如果不是這樣,記得指正 T.T)
Color.find這個(gè)方法是哪來(lái)的?在這里,我們將 URL 處理的代碼放到模型里,而不是放到控制器里。當(dāng)需要得到一個(gè)Color對(duì)象的時(shí)候,只需要我們傳遞個(gè)block進(jìn)去,不用在控制器中去寫重復(fù)的代碼了。

給Color類添加find類方法:

class Color...def self.find(hex, &block)BW::HTTP.get("http://www.colr.org/json/color/#hex") do |response|p response.body.to_str# for now, pass nil.block.call(nil)endend end

(譯者注:RubyMotion中的block。如果困惑或者想深入研究,可以去看看Ruby的lambda,還有RubyMotion的block傳遞)

有些困惑?我們使用簡(jiǎn)單的HTTP.get去請(qǐng)求服務(wù)器,得到數(shù)據(jù),然后通過&block傳出去。調(diào)用的時(shí)候,請(qǐng)求調(diào)用完畢后,會(huì)執(zhí)行調(diào)用的時(shí)候do/end之間的代碼。通過.call(some, variables)執(zhí)行do |some, variables|。

再rake一下,來(lái)個(gè)數(shù)據(jù)測(cè)試一下這個(gè)方法,如:3B5998。你將在終端中看到:

(main)> "\"colors\": [{\"timestamp\": 1285886579, \"hex\": \"ff00ff\", \"id\": 3976, \"tags\": [{\"timestamp\": 1108110851, \"id\": 2583, \"name\": \"fuchsia\"}, {\"timestamp\": 1108110864, \"id\": 3810, \"name\": \"magenta\"}, {\"timestamp\": 1108110870, \"id\": 4166, \"name\": \"magic\"}, {\"timestamp\": 1108110851, \"id\": 2626, \"name\": \"pink\"}, {\"timestamp\": 1240447803, \"id\": 24479, \"name\": \"rgba8b24ff00ff\"}, {\"timestamp\": 1108110864, \"id\": 3810, \"name\": \"magenta\"}]], \"schemes\": [], \"schemes_history\": , \"success\": true, \"colors_history\": \"ff00ff\": [{\"d_count\": 0, \"id\": \"4166\", \"a_count\": 1, \"name\": \"magic\"}, {\"d_count\": 0, \"id\": \"2626\", \"a_count\": 1, \"name\": \"pink\"}, {\"d_count\": 0, \"id\": \"24479\", \"a_count\": 1, \"name\": \"rgba8b24ff00ff\"}, {\"d_count\": 0, \"id\": \"3810\", \"a_count\": 1, \"name\": \"magenta\"}], \"messages\": [], \"new_color\": \"ff00ff\"}\n"

WTF!!一坨JSON字符串啊,親我不想要字符串啊,能不能給我Ruby的Hash?

在BubbleWrap里已經(jīng)集成了解析JSON的方法:BW::JSON.parse,開箱即用:

def self.find(hex, &block)BW::HTTP.get("http://www.colr.org/json/color/#hex") do |response|result_data = BW::JSON.parse(response.body.to_str)color_data = result_data["colors"][0]# Colr will return a color with id == -1 if no color was foundcolor = Color.new(color_data)if color.id.to_i == -1block.call(nil)elseblock.call(color)endend end

在我們的SearchController中,要做一些對(duì)無(wú)效輸入的校驗(yàn):

def viewDidLoad...Color.find(hex) do |color|if color.nil?@search.setTitle("None :(", forState: UIControlStateNormal)else@search.setTitle("Search", forState: UIControlStateNormal)self.open_color(color)end@search.enabled = true@text_field.enabled = trueendendenddef open_color(color)p "Opening #color"end

一切看起來(lái)很好。當(dāng)遇到無(wú)效的JSON的時(shí)候界面上會(huì)給出明確的反饋:

現(xiàn)在改補(bǔ)上 open_color 方法的代碼了。它push一個(gè)ColorController,然后在其中顯示顏色。

def open_color(color)self.navigationController.pushViewController(ColorController.alloc.initWithColor(color), animated:true) end

ColorController

我們要自定義ColorController的構(gòu)造函數(shù)。這個(gè)Controller的視圖有兩部分:一個(gè)UITableView,用來(lái)顯示顏色標(biāo)記,一個(gè)Section 顯示具體顏色和添加新的標(biāo)記。當(dāng)我們想要標(biāo)記一個(gè)顏色的時(shí)候,我們要發(fā)一個(gè)請(qǐng)求,然后再刷新讓它顯示出來(lái)。

不嘴炮了,看看代碼:

class ColorController < UIViewControllerattr_accessor :colordef initWithColor(color)initWithNibName(nil, bundle:nil)self.color = colorselfend...

當(dāng)重載一個(gè)iOS SDK 構(gòu)造函數(shù)的時(shí)候,你需要做兩件事:調(diào)用它的父構(gòu)造函數(shù);在函數(shù)結(jié)尾的時(shí)候返回初始化過的它自己。在RubyMotion中,你不能像標(biāo)準(zhǔn)Ruby一樣初始化。

初始化完畢,該布局了:

def viewDidLoadsuperself.title = self.color.hex# You must comment out the following line if you are developing on iOS < 7.self.edgesForExtendedLayout = UIRectEdgeNone# A light grey background to separate the Tag table from the Color info@info_container = UIView.alloc.initWithFrame [[0, 0], [self.view.frame.size.width, 110]]@info_container.backgroundColor = UIColor.lightGrayColorself.view.addSubview @info_container# A visual preview of the actual color@color_view = UIView.alloc.initWithFrame [[10, 10], [90, 90]]# String#to_color is another handy BubbbleWrap addition!@color_view.backgroundColor = String.new(self.color.hex).to_colorself.view.addSubview @color_view# Displays the hex code of our color@color_label = UILabel.alloc.initWithFrame [[110, 30], [0, 0]]@color_label.text = self.color.hex@color_label.sizeToFitself.view.addSubview @color_label# Where we enter the new tag@text_field = UITextField.alloc.initWithFrame [[110, 60], [100, 26]]@text_field.placeholder = "tag"@text_field.textAlignment = UITextAlignmentCenter@text_field.autocapitalizationType = UITextAutocapitalizationTypeNone@text_field.borderStyle = UITextBorderStyleRoundedRectself.view.addSubview @text_field# Tapping this adds the tag.@add = UIButton.buttonWithType(UIButtonTypeRoundedRect)@add.setTitle("Add", forState:UIControlStateNormal)@add.setTitle("Adding...", forState:UIControlStateDisabled)@add.setTitleColor(UIColor.lightGrayColor, forState:UIControlStateDisabled)@add.sizeToFit@add.frame = [[@text_field.frame.origin.x + @text_field.frame.size.width + 10, @text_field.frame.origin.y],@add.frame.size]self.view.addSubview(@add)# The table for our color's tags.table_frame = [[0, @info_container.frame.size.height],[self.view.bounds.size.width, self.view.bounds.size.height - @info_container.frame.size.height - self.navigationController.navigationBar.frame.size.height]]@table_view = UITableView.alloc.initWithFrame(table_frame, style:UITableViewStylePlain)self.view.addSubview(@table_view)end

……好大一坨代碼啊!不要慌,這些代碼很容易理解,我們只是添加了幾個(gè)子view。

rake一下試試看?

額……真的很丑啊……

處理tags沒啥特別的,就是實(shí)現(xiàn)一個(gè)delegate。

def viewDidLoad...@table_view.dataSource = selfenddef tableView(tableView, numberOfRowsInSection:section)self.color.tags.countenddef tableView(tableView, cellForRowAtIndexPath:indexPath)@reuseIdentifier ||= "CELL_IDENTIFIER"cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier) || beginUITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:@reuseIdentifier)endcell.textLabel.text = self.color.tags[indexPath.row].namecellend

再次運(yùn)行rake,有點(diǎn)意思了吧?

!()[http://rubymotion-tutorial.com/10-api-driven-example/images/4.png]

接下來(lái)要添加新的tags,有多種方法去實(shí)現(xiàn)。你可以老老實(shí)實(shí)的Tag.create(tag),也可以使用Ruby的黑魔法color.tags << tag,但為了體現(xiàn)出Color和Tag存在聯(lián)系,我們這么做:color.add_tag(tag, &block)。

這個(gè)方法實(shí)現(xiàn)如下::

def add_tag(tag, &block)BW::HTTP.post("http://www.colr.org/js/color/#{self.hex}/addtag/", payload: {tags: tag}) do |response|block.callendend

最后那個(gè)參數(shù)是在請(qǐng)求執(zhí)行結(jié)束后回調(diào)的。好的做法是分別處理成功和失敗兩種情況,這個(gè)例子為了簡(jiǎn)單,就先不考慮了。

現(xiàn)在給ColorController的按鈕添加事件處理代碼。我們想在Tag被發(fā)送到服務(wù)器之后,根據(jù)當(dāng)前服務(wù)器返回的數(shù)據(jù)刷新:

def viewDidLoad...self.view.addSubview(@add)@add.when(UIControlEventTouchUpInside) do@add.enabled = false@text_field.enabled = falseself.color.add_tag(@text_field.text) dorefreshendend...enddef refreshColor.find(self.color.hex) do |color|self.color = color@table_view.reloadData@add.enabled = true@text_field.enabled = trueendend

我們給@add按鈕添加了UIControlEventTouchUpInside事件,在事件觸發(fā)的時(shí)候,會(huì)POST添加請(qǐng)求給服務(wù)器。當(dāng)請(qǐng)求處理結(jié)束,我們刷新頁(yè)面。這將觸發(fā)Color.find,重設(shè)我們的數(shù)據(jù)。

rake一下,添加tag試試?

時(shí)候到溜

這片冗長(zhǎng)的教程終于要結(jié)束了。在教程中,我們分離了Controller和Model,因?yàn)橐3质纠銐蛐?#xff0c;沒怎么考慮View,如果要考慮View,就需要引入KVO或類似的技術(shù)。作為預(yù)覽,本文的示例已經(jīng)足夠給力了。

到底講了點(diǎn)啥?

  • 使用Model處理你的JSON數(shù)據(jù),而不是使用Dictionary或Hash
  • 把請(qǐng)求放到了Model中
  • Controller 響應(yīng)用戶事件
  • 在請(qǐng)求執(zhí)行過程中,阻塞界面

總結(jié)

以上是生活随笔為你收集整理的RubyMotion 指南:API 驱动开发示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。