RubyMotion 가이드: API 구동 개발 예시

18144 단어 cocoaiosruby
@ shiweifu 본문 링크:http://segmentfault.com/blog/shiweifu 원본 링크:http://rubymotion-tutorial.com/10-api-driven-example/ 목표 독자: ["RubyMotion 개발 모델 을 알 고 싶다", "RubyMotion 을 배우 고 싶다", "웃 기기"]
백 엔 드 로 Colr JSON API 를 사용 하 는 애플 리 케 이 션 을 만 들 것 입 니 다.사용자 가 색상 의 16 진수 (\ # 3B 5998) 를 입력 하면 탭 의 색상 이 변 하 는 것 을 볼 수 있 습 니 다.그들 은 안에 새로운 색깔 을 추가 할 수 있다.
우 리 는 먼저 프로그램의 구 조 를 고려 해 보 자.두 개 Controller 가 있 습 니 다. 하 나 는 검색 에 사용 되 고 하 나 는 색 을 표시 하 는 데 사 용 됩 니 다.이 두 개 Controller 는 바깥 에 모두 끼 워 져 있다 UINavigationController.우 리 는 Model: Color, Tag 더 필요 하 다. 그것 은 아름 답지 않 을 수도 있 지만 일 을 할 수 있다.
초기 화motion create Colr 명령 을 사용 하여 새 항목 을 초기 화하 고 bubble-wrap 당신 의 Rakefile 에 추가 합 니 다.다음 에 우 리 는 ./app 에서 두 개의 디 렉 터 리 를 만 듭 니 다. ./app/models/./app/controllers.
Models
우선 모형 부터 봅 시다.Colr API 의 Color JSON 구 조 는 다음 과 같 습 니 다.
{
  "timestamp": 1285886579,
  "hex": "ff00ff",
  "id": 3976,
  "tags": [{
    "timestamp": 1108110851,
    "id": 2583,
    "name": "fuchsia"
  }]
}

우리 의 Colors 는 timestamp, hex, id, tags 이 속성 들 이 필요 하 다. 특히 tags 속성 은 여러 개 Tag 대상 을 포함 할 것 이다.
만 들 기 ./app/models/color.rb 그리고 Model 코드 를 입력 하 십시오:
class Color
  PROPERTIES = [:timestamp, :hex, :id, :tags]
  PROPERTIES.each { |prop|
    attr_accessor prop
  }

  def initialize(hash = )
    hash.each { |key, value|
      if PROPERTIES.member? key.to_sym
        self.send((key.to_s + "=").to_s, value)
      end
    }
  end

  ...
PROPERTIES 이것 은 작은 trick 로 속성 을 쉽게 정의 할 수 있 습 니 다.조금 더 말씀 드 려 야 할 것 은 tags 이 속성 입 니 다. Tag Model 의 배열 을 되 돌려 줍 니 다.
 ...

  def tags
    @tags ||= []
  end

  def tags=(tags)
    if tags.first.is_a? Hash
      tags = tags.collect  |tag| Tag.new(tag) 
    end

    tags.each { |tag|
      if not tag.is_a? Tag
        raise "Wrong class for attempted tag #tag.inspect"
      end
    }

    @tags = tags
  end
end

우 리 는 #tags 의 getter 와 setter 를 덮어 썼 기 때문에 tags 값 이 없 을 때 빈 배열 로 돌아 갑 니 다.#tags= 대상 배열 의 해석 과 반환 을 보증 합 니 다.다음은 모델 안에 무엇이 있 는 지 짜 보 자.
만 들 고 열기 Tag 인터페이스 에서 돌아 오 는 데 이 터 는 다음 과 같 습 니 다.
{
  "timestamp": 1108110851,
  "id": 2583,
  "name": "fuchsia"
}

모델 의 클래스 를 만 듭 니 다. 코드 가 짧 고 우호 적 입 니 다.
class Tag
  PROPERTIES = [:timestamp, :id, :name]
  PROPERTIES.each { |prop|
    attr_accessor prop
  }

  def initialize(hash = )
    hash.each { |key, value|
      if PROPERTIES.member? key.to_sym
        self.send((key.to_s + "=").to_s, value)
      end
    }
  end
end

Controllers
모델 이 이미 정의 되 었 습 니 다. 당신 의 친구 '컨트롤 러 군' 이 곧 출시 될 것 입 니 다.Tag./app/models/tag.rb 두 파일 을 만 들 고 가장 기본 적 인 실현 을 먼저 작성 합 니 다.
class SearchController < UIViewController
  def viewDidLoad
    super

    self.title = "Search"
  end
end
class ColorController < UIViewController
  def viewDidLoad
    super

    self.title = "Color"
  end
end

우리 의 컨트롤 러 Tag./app/controllers/search_controller.rb 를 가지 고 ./app/controllers/color_controller.rb 에 게 던 집 니 다.
class AppDelegate
  def 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.makeKeyAndVisible
    true
  end
end

코드 가 쌓 였 습 니 다. 성 과 를 볼 때 가 되 었 습 니 다. UINavigationController 명령 을 실행 하면 화면 에 나타 납 니 다.
RubyMotion 指南:API 驱动开发示例_第1张图片
모든 것 이 다 좋 으 니 안에 무엇이 있 는 지 봐 야 한다.
SearchController
(역자 저: 원문 은 시리즈 문장 으로 이전의 부분 에 나타 난 적 이 없다 UIWindow. 그래서 여기 서 가설 AppDelegate 이 나타 난 적 이 없다. 그렇지 않 으 면 연결 되 지 않 는 다.)
저 희 는 이전에 언급 하지 않 았 던 컨트롤 rake 을 사용 하여 사용자 의 입력 을 받 아들 일 것 입 니 다. 사용자 가 SearchController 단 추 를 누 르 면 저 희 는 API 요청 을 할 것 입 니 다. 이 때 화면 은 요청 이 끝 날 때 까지 어떠한 입력 도 받 아들 이지 않 습 니 다.요청 이 성공 적 으로 완료 되면 push UITextField 에서 결 과 를 보 여 줍 니 다. 그렇지 않 으 면 오류 알림 을 드 립 니 다.
다음은 UITextField 초기 화 할 때 일 하 는 코드 입 니 다.
def viewDidLoad
    super

    self.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 @search
  end
UITextField 좌표 와 크기 를 설정 하 는 코드 는 제 개인 적 인 습관 입 니 다. 설정 Search 은 차단 할 때의 스타일 을 통일 적 으로 설정 하기 위해 서 입 니 다.ColorControllerSearchController 의 스타일 을 설정 하여 더욱 좋 은 느낌 을 주기 위해 서 이다.self.view.frame.size.height / 2 - 100 다시 실행 합 니 다. 지금 보 이 는 모습:
RubyMotion 指南:API 驱动开发示例_第2张图片
(번역자 주: Bubble Wrap 은 Ruby Motion 이 공식 적 으로 개발 한 라 이브 러 리 로 코코아 로 써 매우 아 픈 곳 을 많이 봉 하여 코드 를 더욱 'Ruby' 로 만 들 었 다)
사건 처리 해 야 지.내 가 전에 UIControlStateDisabled 찌 질 하 다 고 했 던 거 기억 나?그것 을 사용 하면 우 리 는 과거 에 바보 같은 UITextBorderStyleRoundedRect 이 벤트 를 추가 하지 않 아 도 된다. 코드 가 매우 뚜렷 하 다.
  def viewDidLoad
    ...

    self.view.addSubview @search

    @search.when(UIControlEventTouchUpInside) do
      @search.enabled = false
      @text_field.enabled = false

      hex = @text_field.text
      # chop off any leading #s
      hex = hex[1..-1] if hex[0] == "#"

      Color.find(hex) do |color|
        @search.enabled = true
        @text_field.enabled = true
      end
    end
  end
UITexitField 방법 은 모든 rake 의 하위 클래스 에서 사용 할 수 있다.BubbleWrap 로 시작 하 는 표지 이벤트 위 치 를 매개 변수 로 사용 합 니 다.요청 을 보 낸 후, 우 리 는 임시로 UI 를 사용 하지 않 습 니 다.
(번역자 주: 작가 의 뜻 은 모든 색깔 에 코드 를 써 서 얻 는 것 일 것 입 니 다. 의문 이 있 으 면 원문 을 보 세 요. 그렇지 않 으 면 T. T addTarget:action:forControlEvents when 라 는 방법 이 어디서 났 는 지 기억 하 세 요.컨트롤 러 가 아 닌 URL 처리 코드 를 모델 에 넣 습 니 다.Color 대상 을 얻 으 려 면 block 을 전달 해 야 합 니 다. 컨트롤 러 에 중복 되 는 코드 를 쓰 지 않 아 도 됩 니 다.UIControl 클래스 에 UIControlEvent 클래스 를 추가 하 는 방법:
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)
    end
  end
end

(번역자: Ruby Motion 의 block. 곤 혹 스 럽 거나 깊이 연구 하고 싶다 면 Ruby 의 lambda, 그리고 Ruby Motion 의 block 전달 을 보 세 요)
좀 곤 혹 스 러 워 요?우 리 는 간단 한 Color.find 을 사용 하여 서버 에 요청 하고 데 이 터 를 얻 은 후에 Color 를 통 해 전달 합 니 다.호출 할 때 호출 요청 이 완료 되면 호출 할 때 find 사이 의 코드 를 실행 합 니 다.HTTP.get 을 통 해 집행 &block.
다시 do/end 한 번 데 이 터 를 테스트 해 보 세 요. 예 를 들 어 .call(some, variables).터미널 에서 볼 수 있 습 니 다:
(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\"}
"

WTF!!JSON 문자열 이 네요. 문자열 을 원 하지 않 는 다 고 뽀뽀 해 주세요. Ruby Hash 좀 주 시 겠 어 요?
Bubble Wrap 에 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 found
    color = Color.new(color_data)
    if color.id.to_i == -1
      block.call(nil)
    else
      block.call(color)
    end
  end
end

우리 의 Search Controller 에서 잘못된 입력 에 대한 검 사 를 해 야 합 니 다.
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 = true
      end
    end
  end

  def open_color(color)
    p "Opening #color"
  end

모든 것 이 좋아 보인다.잘못된 JSON 을 만 났 을 때 화면 에 명확 한 피드백 을 줍 니 다.
RubyMotion 指南:API 驱动开发示例_第3张图片
이제 do |some, variables| 방법의 코드 를 바 꾸 었 다.push 하나 rake 를 사용 한 다음 색상 을 표시 합 니 다.
def open_color(color)
  self.navigationController.pushViewController(ColorController.alloc.initWithColor(color), animated:true)
end

ColorController
우 리 는 3B5998 의 구조 함 수 를 사용자 정의 해 야 한다.이 open_color 보 기 는 두 부분 이 있 습 니 다. 하나의 UITableView 는 색상 표 시 를 표시 하고 하나의 Section 은 구체 적 인 색상 을 표시 하 며 새로운 표 시 를 추가 합 니 다.색상 을 표시 하려 면 요청 을 보 내 고 새로 고침 을 해서 표시 해 야 합 니 다.
입 을 다 물 지 않 고 코드 를 보 세 요.
class ColorController < UIViewController
  attr_accessor :color

  def initWithColor(color)
    initWithNibName(nil, bundle:nil)
    self.color = color
    self
  end

  ...


iOS SDK 구조 함 수 를 다시 불 러 올 때 두 가지 일 을 해 야 합 니 다. 부모 구조 함 수 를 호출 합 니 다.함수 가 끝 날 때 초기 화 된 자신 을 되 돌려 줍 니 다.루비 모 션 에 서 는 표준 루비 처럼 초기 화 할 수 없습니다.
초기 화 완료, 이 레이아웃:
  def viewDidLoad
    super

    self.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.lightGrayColor
    self.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_color
    self.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.sizeToFit
    self.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 = UITextBorderStyleRoundedRect
    self.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

.............................................................당황 하지 마 세 요. 이 코드 들 은 쉽게 이해 할 수 있 습 니 다. 우 리 는 단지 몇 개의 키 view 를 추 가 했 을 뿐 입 니 다.ColorController 한번 해 볼 까요?
RubyMotion 指南:API 驱动开发示例_第4张图片
으.. 정말 못 생 겼 다..
tags 를 처리 하 는 것 은 특별한 것 이 아니 라 delegate 를 실현 하 는 것 이다.
def viewDidLoad
    ...

    @table_view.dataSource = self
  end

  def tableView(tableView, numberOfRowsInSection:section)
    self.color.tags.count
  end

  def tableView(tableView, cellForRowAtIndexPath:indexPath)
    @reuseIdentifier ||= "CELL_IDENTIFIER"

    cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier) || begin
      UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:@reuseIdentifier)
    end

    cell.textLabel.text = self.color.tags[indexPath.row].name

    cell
  end

다시 운행 ColorController, 재 미 있 죠?
!()[http://rubymotion-tutorial.com/10-api-driven-example/images/4.png]
다음은 새로운 tags 를 추가 하려 면 여러 가지 방법 이 있 습 니 다.당신 은 성실 하 게 Controller 할 수도 있 고 Ruby 의 흑 마법 rake 을 사용 할 수도 있 습 니 다. 그러나 Color 와 Tag 의 관 계 를 나타 내기 위해 우 리 는 이렇게 합 니 다. rake이 방법 은 다음 과 같다.
  def add_tag(tag, &block)
    BW::HTTP.post("http://www.colr.org/js/color/#{self.hex}/addtag/", payload: {tags: tag}) do |response|
      block.call
    end
  end

마지막 으로 그 매개 변 수 는 요청 실행 이 끝 난 후에 리 셋 된 것 입 니 다.좋 은 방법 은 성공 과 실패 두 가지 상황 을 각각 처리 하 는 것 이다. 이 예 는 간단 하기 위해 먼저 고려 하지 않 는 다.
현재 Tag.create(tag) 버튼 에 이벤트 처리 코드 를 추가 합 니 다.태그 가 서버 에 전송 되면 현재 서버 에서 돌아 오 는 데이터 에 따라 새로 고침 하고 싶 습 니 다.
  def viewDidLoad
    ...

    self.view.addSubview(@add)

    @add.when(UIControlEventTouchUpInside) do
      @add.enabled = false
      @text_field.enabled = false
      self.color.add_tag(@text_field.text) do
        refresh
      end
    end

    ...
  end

  def refresh
    Color.find(self.color.hex) do |color|
      self.color = color

      @table_view.reloadData

      @add.enabled = true
      @text_field.enabled = true
    end
  end

@ add 버튼 에 이벤트 color.tags << tag 를 추 가 했 습 니 다. 이벤트 가 실 행 될 때 POST 에서 서버 에 요청 을 추가 합 니 다.요청 처리 가 끝나 면 페이지 를 새로 고 칩 니 다.이것 은 우리 의 데 이 터 를 재 설정 하기 위해 촉발 color.add_tag(tag, &block) 할 것 이다.ColorController 한번, tag 를 추가 해 볼 까요?
때 가 되다
이 지루 한 교정 이 마침내 끝 날 것 이다.튜 토리 얼 에서 우 리 는 UIControlEventTouchUpInsideColor.find 를 분리 했다. 예 시 를 충분히 작 게 유지 하려 면 별로 고려 하지 않 았 기 때문이다 rake. Controller 를 고려 하려 면 KVO 나 비슷 한 기술 을 도입 해 야 한다.미리 보기 로 서 본문의 예 시 는 이미 충분 하 다.
도대체 무슨 얘 기 를 한 거 야?
  • 사용 Model 이 아 닌 View 데 이 터 를 처리 합 니 다 View 또는 Model
  • 요청 을 JSON 에 넣 었 습 니 다
  • Dictionary 사용자 이벤트 에 응답
  • 요청 실행 과정 에서 인터페이스 차단
  • 좋은 웹페이지 즐겨찾기