Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Use objc_util and NSURLConnection to make a GET request
-
Hi.
Since pythonista does not handle ipv6, I would like to make a method for objc_util, that can be a replacement for python request.
A objc_util replacement for a call like this:
import requests root='http://validate.jsontest.com' url=root+'' params = {'json':str({"key":"value"})} r = requests.get(url, params=params) print r.json()
-
I am here at the moment
from objc_util import * class Web(object): def __init__(self, root=None, method=None, headers=None): #NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; self.request = ObjCClass('NSMutableURLRequest').alloc().initWithURL_(nsurl(root)) #[request setHTTPMethod:@"POST"]; self.request.setHTTPMethod_(method) # Make headers for key in headers: #[request setValue:@"es" forHTTPHeaderField:@"Accept-Language"]; self.request.setValue_forHTTPHeaderField_(key, headers[key]) # Make request #NSURLConnection * theConnection = [[NSURLConnection alloc] initWithRequest:imageRequest delegate:self]; #self.conn = ObjCClass('NSURLConnection').alloc().initWithRequest_delegate_(self.request, self) self.conn = ObjCClass('NSURLConnection').alloc().initWithRequest_delegate_startImmediately_(self.request, self, True) #[connection autorelease]; self.conn.autorelease()
But I dont know how to unpack or return the request?
So I get the response from the server? -
NSURLConnection
was deprecated with iOS 9. However, you can use its replacement,NSURLSession
.This is a very basic example of how to use
NSURLSession
with parameters and how to get the response.
You can pass your parameters as a dictionary as second argument to thevalidate
method.
I think @omz advised against usingobjc_util.retain_global
, but it's necessary in this example to prevent the block from getting released before its getting called by the URL session.In a proper implementation, you probably want to create a Python class so that you can store the completion handler.
#!/usr/bin/env python3 import objc_util import urllib.parse from ctypes import c_void_p NSURLRequest = objc_util.ObjCClass("NSURLRequest") NSURLSession = objc_util.ObjCClass("NSURLSession") NSURLSessionConfiguration = objc_util.ObjCClass("NSURLSessionConfiguration") def validate(url, params, responseHandler): if params: params_encoded = urllib.parse.urlencode(params) else: params_encoded = "" url = objc_util.nsurl("{}?{}".format(url, params_encoded)) request = NSURLRequest.request(URL=url) configuration = NSURLSessionConfiguration.defaultSessionConfiguration() session = NSURLSession.session(Configuration=configuration) completionHandler = objc_util.ObjCBlock(responseHandler, restype=None, argtypes=[c_void_p, c_void_p, c_void_p, c_void_p]) objc_util.retain_global(completionHandler) dataTask = session.dataTask(Request=request, completionHandler=completionHandler) dataTask.resume() def responseHandlerBlock(_cmd, data, response, error): if error is not None: error = objc_util.ObjCInstance(error) print(error) return response = objc_util.ObjCInstance(response) data = objc_util.ObjCInstance(data) print(str(objc_util.nsdata_to_bytes(data))) url = "http://validate.jsontest.com" params = {"json" : {"first" : "lukas", "last" : "kollmer"}} validate(url, None, responseHandlerBlock)
-
WOW!!!!
Thanks! :)
This works as expected. :)I get a json back, I can work with.
I will try to implement this, and see if it passes the Apple review.Thanks!
import objc_util from urlparse import urlparse from urllib import urlencode from ctypes import c_void_p NSURLRequest = objc_util.ObjCClass("NSURLRequest") NSURLSession = objc_util.ObjCClass("NSURLSession") NSURLSessionConfiguration = objc_util.ObjCClass("NSURLSessionConfiguration") def validate(url, params, responseHandler): if params: params_encoded = urlencode(params) else: params_encoded = "" url = objc_util.nsurl("{}?{}".format(url, params_encoded)) request = NSURLRequest.request(URL=url) configuration = NSURLSessionConfiguration.defaultSessionConfiguration() session = NSURLSession.session(Configuration=configuration) completionHandler = objc_util.ObjCBlock(responseHandler, restype=None, argtypes=[c_void_p, c_void_p, c_void_p, c_void_p]) objc_util.retain_global(completionHandler) dataTask = session.dataTask(Request=request, completionHandler=completionHandler) dataTask.resume() def responseHandlerBlock(_cmd, data, response, error): if error is not None: error = objc_util.ObjCInstance(error) print(error) return response = objc_util.ObjCInstance(response) data = objc_util.ObjCInstance(data) print(str(objc_util.nsdata_to_bytes(data))) url = "http://validate.jsontest.com" params = {"json" : {"first" : "lukas", "last" : "kollmer"}} #validate(url, None, responseHandlerBlock) validate(url, params, responseHandlerBlock)
-
Now getting a return.
Don't know how to exactly to implement a "wait", but here is a try
import objc_util from urlparse import urlparse from urllib import urlencode from ctypes import c_void_p import time class Web(object): def __init__(self, url=None, params=None): self.data = None if params: params_encoded = urlencode(params) else: params_encoded = "" url = objc_util.nsurl("{}?{}".format(url, params_encoded)) request = objc_util.ObjCClass("NSURLRequest").request(URL=url) configuration = objc_util.ObjCClass("NSURLSessionConfiguration").defaultSessionConfiguration() session = objc_util.ObjCClass("NSURLSession").session(Configuration=configuration) completionHandler = objc_util.ObjCBlock(self.responseHandlerBlock, restype=None, argtypes=[c_void_p, c_void_p, c_void_p, c_void_p]) objc_util.retain_global(completionHandler) dataTask = session.dataTask(Request=request, completionHandler=completionHandler) dataTask.resume() def responseHandlerBlock(self, _cmd, data, response, error): if error is not None: error = objc_util.ObjCInstance(error) print(error) return response = objc_util.ObjCInstance(response) data = objc_util.ObjCInstance(data) self.data = (str(objc_util.nsdata_to_bytes(data))) def return_data(self): return self.data url = "http://validate.jsontest.com" params = {"json" : {"first" : "lukas", "last" : "kollmer"}} #validate(url, None, responseHandlerBlock) #validate(url, params, responseHandlerBlock) call = Web(url, params) wait = True while wait: data = call.return_data() if data != None: print data wait = False print "Done"```
-
I got it to work with, headers, ios basic authentication and parameters, and saving the response.
Thanks!
https://gist.github.com/tlinnet/31b35136e206ea2b4829a13799c89316
-
And now the last modification..
Making exceptions work as well.
https://gist.github.com/tlinnet/aff5decf31d07d0c0cccfad7961353f7
-
If your app is doing a lot of this, be careful that there may be a memory leak. you may need to use
someobject ._cached_methods.clear()
for every ObjCInstance that you create inside the callback, which breaks a reference cycle (well, at least untangles it a bit so gc can handle it)