AFMotion
AFMotion is a thin RubyMotion wrapper for AFNetworking, the absolute best networking library on iOS and OS X.
Usage
AFMotion can be used with standalone URL requests:
AFMotion::HTTP.get("http://google.com") do |result|
p result.body
end
AFMotion::JSON.get("http://jsonip.com") do |result|
p result.object["ip"]
end
Web Services
@client = AFMotion::... # create your client
@client.get("stream/0/posts/stream/global") do |result|
if result.success?
p (result.operation || result.task) # depending on your client
elsif result.failure?
p result.error.localizedDescription
end
end
Migration from AFMotion 2.x
Breaking Change
Parameters must now be specified with the params:
keyword arg.
AFMotion 2.x
AFMotion::HTTP.get("http://google.com", q: "rubymotion") do |result|
# sends request to http://google.com?q=rubymotion
end
AFMotion 3.x
AFMotion::HTTP.get("http://google.com", params: { q: "rubymotion" }) do |result|
# sends request to http://google.com?q=rubymotion
end
This allows you to also pass in a progress_block or additional headers on the fly:
AFMotion::HTTP.get("http://url.com/large_file.mov", params: { quality: "high" }, progress_block: proc { |progress| update_progress(progress) }, headers: {}) do |result|
# sends request to http://google.com?q=rubymotion
end
For grouping similar requests (AFHTTPSession), use AFMotion::Client
(now exactly the same as AFMotion::SessionClient
)
AFMotion::Client
If you're interacting with a web service, you can use AFHTTPRequestOperationManager
with this nice wrapper:
# DSL Mapping to properties of AFHTTPRequestOperationManager
@client = AFMotion::Client.build("https://alpha-api.app.net/") do
header "Accept", "application/json"
response_serializer :json
end
Images
Loading images from the internet is pretty common. AFNetworking's existing methods aren't bad at all, but just incase you want extra Ruby:
image_view = UIImageView.alloc.initWithFrame CGRectMake(0, 0, 100, 100)
image_view.url = "http://i.imgur.com/r4uwx.jpg"
# or
placeholder = UIImage.imageNamed "placeholder-avatar"
image_view.url = {url: "http://i.imgur.com/r4uwx.jpg", placeholder: placeholder}
You can also request arbitrary images:
AFMotion::Image.get("https://www.google.com/images/srpr/logo3w.png") do |result|
image_view = UIImageView.alloc.initWithImage(result.object)
end
Install
-
gem install afmotion
-
require 'afmotion'
or add to yourGemfile
(gem 'afmotion'
) -
rake pod:install
Overview
Results
Each AFMotion wrapper callback yields an AFMotion::HTTPResult
object. This object has properties like so:
AFMotion::some_function do |result|
p result.task.inspect
p result.status_code
if result.success?
# result.object depends on the type of operation.
# For JSON and PLIST, this is usually a Hash.
# For XML, this is an NSXMLParser
# For HTTP, this is an NSURLResponse
# For Image, this is a UIImage
p result.object
elsif result.failure?
# result.error is an NSError
p result.error.localizedDescription
end
end
One-off Requests
There are wrappers which automatically run a URL request for a given URL and HTTP method, of the form:
AFMotion::[Operation Type].[HTTP method](url, [Parameters = {}]) do |result|
...
end
Example:
AFMotion::HTTP.get("http://google.com", params: { q: "rubymotion" }) do |result|
# sends request to http://google.com?q=rubymotion
end
AFMotion::HTTP.get/post/put/patch/delete(url)...
AFMotion::JSON.get/post/put/patch/delete(url)...
AFMotion::XML.get/post/put/patch/delete(url)...
AFMotion::PLIST.get/post/put/patch/delete(url)...
AFMotion::Image.get/post/put/patch/delete(url)...
HTTP Client
If you're constantly accesing a web service, it's a good idea to use an AFHTTPSessionManager
. Things lets you add a common base URL and request headers to all the requests issued through it, like so:
client = AFMotion::Client.build("https://alpha-api.app.net/") do
header "Accept", "application/json"
response_serializer :json
end
client.get("stream/0/posts/stream/global") do |result|
# result.operation exists
...
end
If you're constantly used one web service, you can use the AFMotion::Client.shared
variable have a common reference. It can be set like a normal variable or created with AFMotion::Client.build_shared
.
AFHTTPRequestOperationManager
& AFHTTPSessionManager
support methods of the form Client#get/post/put/patch/delete(url, request_parameters)
. The request_parameters
is a hash containing your parameters to attach as the request body or URL parameters, depending on request type. For example:
client.get("users", params: { id: 1 }) do |result|
...
end
client.post("users", params: { name: "@clayallsopp", library: "AFMotion" }) do |result|
...
end
Multipart Requests
AFHTTPSessionManager
support multipart form requests (i.e. for image uploading) - simply use multipart_post
and it'll convert your parameters into properly encoded multipart data. For all other types of request data, use the form_data
object passed to your callback:
# an instance of UIImage
image = my_function.get_image
data = UIImagePNGRepresentation(image)
client.multipart_post("avatars") do |result, form_data|
if form_data
# Called before request runs
# see: http://cocoadocs.org/docsets/AFNetworking/2.5.0/Protocols/AFMultipartFormData.html
form_data.appendPartWithFileData(data, name: "avatar", fileName:"avatar.png", mimeType: "image/png")
elsif result.success?
...
else
...
end
end
This is an instance of AFMultipartFormData
.
If you want to track upload progress, simply add a progress_block (Taking a single arg: NSProgress
)
client.multipart_post("avatars", progress_block: proc { |progress| update_progress(progress) }) do |result, form_data|
if form_data
# Called before request runs
# see: https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ
form_data.appendPartWithFileData(data, name: "avatar", fileName:"avatar.png", mimeType: "image/png")
else
...
end
Headers
You can set default HTTP headers using client.headers
, which is sort of like a Hash
:
client.headers["Accept"]
#=> "application/json"
client.headers["Accept"] = "something_else"
#=> "application/something_else"
client.headers.delete "Accept"
#=> "application/something_else"
Client Building DSL
The AFMotion::Client
& AFMotion::SessionClient
DSLs allows the following properties:
header(header, value)
authorization(username: ___, password: ____)
for HTTP Basic auth, orauthorization(token: ____)
for Token based auth.request_serializer(serializer)
. Allows you to set anAFURLRequestSerialization
for all your client's requests, which determines how data is encoded on the way to the server. So if your API is always going to be JSON, you should setoperation(:json)
. Accepts:json
and:plist
, or any instance ofAFURLRequestSerialization
and must be called before callingheader
orauthorization
or else the headers will not be applied.response_serializer(serializer)
. Allows you to set anAFURLResponseSerialization
, which determines how data is decoded once the server respnds. Accepts:json
,:xml
,:plist
,:image
,:http
, or any instance ofAFURLResponseSerialization
.
For AFMotion::SessionClient
only:
session_configuration(session_configuration, identifier = nil)
. Allows you to set theNSURLSessionConfiguration
. Accepts:default
,:ephemeral
,:background
(with theidentifier
as a String), or an instance ofNSURLSessionConfiguration
.
You can also configure your client by passing it as a block argument:
client = AFMotion::SessionClient.build("https://alpha-api.app.net/") do |client|
client.session_configuration :default
client.header "Accept", @custom_header
end