Develop the iOS App using the Swift - Part #2
New Features
What feature(s) did you add?
On the basis of the previous version, the following features were updated: steemconnect login, comment, vote, release function
How did you implement it/them?
This function is updated, mainly related to two files.
//
// SteemClient.swift
// SteemThink
//
// Created by zhouzhiwei on 2018/2/22.
// Copyright © 2018年 zijinph. All rights reserved.
//
import UIKit
import MBProgressHUD
let baseURL:String = "https://v2.steemconnect.com"
let appId:String = ""
//GET /get_discussions_by_trending
let discussions_by_trending = "https://api.steemjs.com/get_discussions_by_trending?"
//GET /get_discussions_by_created
let discussions_by_created = "https://api.steemjs.com/get_discussions_by_created?"
//GET /get_discussions_by_hot
let discussions_by_hot = "https://api.steemjs.com/get_discussions_by_hot?"
//GET /get_accounts
let get_accounts = "https://api.steemjs.com/get_accounts?"
let get_content_replies = "https://api.steemjs.com/get_content_replies?"
let get_login_url = "https://v2.steemconnect.com/oauth2/authorize?client_id=steemthink.com&redirect_uri=https://cnsteem.github.io/sc2-angular&scope=vote,comment"
//POST /broadcast
let post_broadcast = "https://v2.steemconnect.com/api/broadcast/"
class STClient: NSObject {
typealias STClientCallBack = (_ response: Any?,_ error: Error?)->()
//MARK: - vote
class func vote(
voter:String,
author:String,
permlink:String,
weight:NSInteger,
finished:@escaping STClientCallBack){
let param = ["voter": voter,
"author": author,
"permlink":permlink,
"weight":weight,
] as [String : Any]
self.broadcast(body: ["operations":[["vote",param]]],finished: finished)
}
//MARK: - post&comment
class func comment(
parentAuthor:String,
parentPermlink:String,
author:String,
permlink:String,
body:String,
finished:@escaping STClientCallBack) {
let param = ["parent_author": parentAuthor,
"parent_permlink": parentPermlink,
"author":author,
"permlink":permlink,
"title":"",
"body":body,
"json_metadata": ""]
self.broadcast(body: ["operations":[["comment",param]]],finished: finished)
}
class func broadcast(body:Dictionary<String, Any>,
finished:@escaping STClientCallBack) {
// print("jsonData ==============="+"\(NSDictionary_STExtension.getJSONStringFromDictionary(dictionary: body))")
self.post(url: post_broadcast, body: body, finished: finished)
}
class func post(url:String,body:Dictionary<String, Any>,finished:@escaping STClientCallBack) -> Void {
let client = STAFNetworkTools.sharedTools;
// Set the requested header tag
client.requestSerializer.setValue(UserDataManager.sharedInstance.getToken(), forHTTPHeaderField: "Authorization")
client.request(method: .POST, urlString: url, parameters: body as AnyObject) { (response, error) in
finished(response,error)
}
}
class func get(url:String!,parameters:AnyObject?,to:UIView?,finished:@escaping STClientCallBack){
var hud:MBProgressHUD?
if (to != nil){
hud = MBProgress_STExtension.ST_ShowHUDAddedToView(view: to!, title: "", animated: true)
}
STAFNetworkTools.sharedTools.request(method: .GET, urlString: url, parameters: parameters) { (response: Any?,error: Error?) in
if (hud != nil) {
hud?.hide(animated: true)
}
if (error != nil) && (to != nil) {
MBProgress_STExtension.ST_ShowHUDHidAfterSecondWithMsgType(title: (error?.localizedDescription)!, view: to!, afterSecond: 1.5, msgType: STMBProgress.Error)
}
finished(response,error)
}
}
}
//
// AFNetworkTools.swift
// SteemThink
//
// Created by zhouzhiwei on 2018/2/22.
// Copyright © 2018 zijinph. All rights reserved.
//
import UIKit
import AFNetworking
/// Request method
/// - GET: get
/// - POST: post
enum AFRequestMethod: String {
case GET = "GET"
case POST = "POST"
}
class STAFNetworkTools: AFHTTPSessionManager {
static let sharedTools: STAFNetworkTools = {
let instance = STAFNetworkTools()
instance.responseSerializer.acceptableContentTypes?.insert("text/html")
instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
instance.requestSerializer = AFJSONRequestSerializer.init()
instance.requestSerializer.timeoutInterval = 20.0
return instance
}()
// (response: AnyObject?, error: NSError?)->()
typealias AFNRequestCallBack = (_ response: Any?,_ error: Error?)->()
///
/// - parameter urlString: request address
/// - parameter parameters: Request parameters
/// - parameter finished: The callback for the success or failure of the request
func request(method: AFRequestMethod = .GET, urlString: String, parameters: AnyObject?, finished:@escaping AFNRequestCallBack){
print("urlString ============ " + urlString)
print("parameters ============ " + String(describing: parameters))
// dataTaskWithHttp is written in the. M file
// corresponds to Swift, is a private modification method
// Define the closure for which the request succeeded
let success = { (dataTask: URLSessionDataTask, responseObject: Any?) -> Void in
print("responseObject =========" + "\(String(describing: responseObject))")
finished(responseObject, nil)
}
// Define the closure of the request failed
let failure = { (dataTask: URLSessionDataTask?, error: Error) -> Void in
print("request Error =========" + error.localizedDescription)
finished(nil, error)
}
if method == .GET {
get(urlString,parameters:parameters,progress:nil,success:success,failure:failure)
}else{
post(urlString, parameters: parameters, progress: nil, success:success, failure: failure)
}
}
func requestBack(method: AFRequestMethod = .GET, urlString: String, parameters: AnyObject?, finished:@escaping AFNRequestCallBack) -> URLSessionDataTask{
print("urlString ============ " + urlString)
print("parameters ============ " + String(describing: parameters))
// dataTaskWithHttp is written in the. M file
// corresponds to Swift, is a private modification method
// Define the closure for which the request succeeded
let success = { (dataTask: URLSessionDataTask, responseObject: Any?) -> Void in
print("responseObject =========" + "\(String(describing: responseObject))")
finished(responseObject, nil)
}
// Define the closure of the request failed
let failure = { (dataTask: URLSessionDataTask?, error: Error) -> Void in
print("request Error =========" + error.localizedDescription)
finished(nil, error)
}
if method == .GET {
return get(urlString,parameters:parameters,progress:nil,success:success,failure:failure)!
}else{
return post(urlString, parameters: parameters, progress: nil, success:success, failure: failure)!
}
}
/// send request (upload file)
func requestWithData(data: NSData, name: String, urlString: String, parameters: AnyObject?, finished:@escaping AFNRequestCallBack) {
// Define the closure for which the request succeeded
let success = { (dataTask: URLSessionDataTask, responseObject: AnyObject?) -> Void in
finished(responseObject, nil)
}
// Define the closure of the request failed
let failure = { (dataTask: URLSessionDataTask?, error: NSError) -> Void in
finished(nil, error)
}
post(urlString, parameters: parameters, constructingBodyWith: { (formData) -> Void in
formData.appendPart(withFileData: data as Data, name: name, fileName: "aa", mimeType: "application/octet-stream")
}, progress: nil, success: success as? (URLSessionDataTask, Any?) -> Void, failure: (failure as! (URLSessionDataTask?, Error) -> Void))
}
}
The following is a detailed code description
The interface part is derived from the sc2.js code in steemconnect-sdk (https://github.com/steemit/steemconnect-sdk/blob/master/src/sc2.js).
Conversion process :
1. HTTPS request header
js:
headers:{
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
Authorization: this.options.accessToken,
}
iOS:
instance.responseSerializer.acceptableContentTypes?.insert("text/html")
instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
instance.requestSerializer = AFJSONRequestSerializer.init()
And we have to set the token, the token is obtained from the login screen callback
let client = STAFNetworkTools.sharedTools;
// Set request header token
client.requestSerializer.setValue(UserDataManager.sharedInstance.getToken(), forHTTPHeaderField: "Authorization")
2. Commenting and publishing articles (Publishing articles and comments is an API, which is a little strange)
js:
SteemConnect.prototype.broadcast = function broadcast(operations, cb) {
return this.send('broadcast', 'POST', { operations }, cb);
};
SteemConnect.prototype.comment = function comment(
parentAuthor,
parentPermlink,
author,
permlink,
title,
body,
jsonMetadata,
cb
) {
const params = {
parent_author: parentAuthor,
parent_permlink: parentPermlink,
author,
permlink,
title,
body,
json_metadata: JSON.stringify(jsonMetadata),
};
return this.broadcast([['comment', params]], cb);
};
iOS:
class func comment(
parentAuthor:String,
parentPermlink:String,
author:String,
permlink:String,
body:String,
finished:@escaping STClientCallBack) {
let param = ["parent_author": parentAuthor,
"parent_permlink": parentPermlink,
"author":author,
"permlink":permlink,
"title":"",
"body":body,
"json_metadata": ""]
self.broadcast(body: ["operations":[["comment",param]]],finished: finished)
}
class func broadcast(body:Dictionary<String, Any>,
finished:@escaping STClientCallBack) {
// print("jsonData ==============="+"\(NSDictionary_STExtension.getJSONStringFromDictionary(dictionary: body))")
self.post(url: post_broadcast, body: body, finished: finished)
}
The contents of the body should be in strict accordance with ["operations": [["comment", param]]] This format, otherwise it will request failure.
3. vote
js:
SteemConnect.prototype.vote = function vote(voter, author, permlink, weight, cb) {
const params = {
voter,
author,
permlink,
weight,
};
return this.broadcast([['vote', params]], cb);
};
iOS:
//MARK: - vote
class func vote(
voter:String,
author:String,
permlink:String,
weight:NSInteger,
finished:@escaping STClientCallBack){
let param = ["voter": voter,
"author": author,
"permlink":permlink,
"weight":weight,
] as [String : Any]
self.broadcast(body: ["operations":[["vote",param]]],finished: finished)
}
Posted on Utopian.io - Rewarding Open Source Contributors
Your contribution cannot be approved because it does not follow the Utopian Rules.
All the code changes have been done in a single commit by the user "zhouzhiwei", thus its very hard to evaluate the contribution. If it is a bigger project we want that it should also have a comprehensive commit history.
You can contact us on Discord.
[utopian-moderator]
Hi @codingdefined
You can find the reason for a single commit here.
https://steemit.com/utopian-io/@steemthinkcom/steemthink-use-angular-and-steem-api-create-steem-blockchain-based-sites
Because another mod(@eastmael) suggested that I separate the ios project from the html project, it would be more clear and convenient to maintain.
So, the submission history of ios items that cannot be seen in this contribution,
But you can see my first submission here.
https://steemit.com/utopian-io/@steemthinkcom/develop-the-ios-app-using-the-swift-part-1
This contribution is based on the previous contribution and has increased, the following features were updated: steemconnect login, comment, vote, release function.
Future ios project updates will find submission records in the same project
If you can please re-review.
Thanks again
Hello @steemthinkcom, thank you for considering my suggestion. @codingdefined did mention the rule:
This is for easier review of the changes done. So i think what you should have done here is make a commit of v1 (without the new features) as your initial/base codes, and another commit for the new features.
I also checked your commit history and i think it would have been best if you committed each feature in a separate pull requests to adhere to the rules.
And i would even suggest to publish a testable version of this app to give moderators the option to test the new features as well.
I support @codingdefined's decision here since I perceive that you overlooked the rule mentioned above.
hi @eastmael,thanks for you reply .
So, your suggestion is to resubmit this contribution as "new project" and provide a test version to facilitate the installation test?
Afterwards, new contributions will be submitted using "New Features" to facilitate mod review?
My suggestion is - do whatever you think is right with your project - focus on its development and adding value to it rather than adhering to rules just so that your contribution will be accepted.
I'm also suggesting to retain this contribution as is rahter than recreating and resubmitting it.
The reason being is that resubmitting it gives me the impression that your only resubmitting for it to be accepted, which is a complete waste of your and our time.
I understand that I will retain this contribution. The next IOS contribution will be based on this contribution.
Thank you for your understanding and looking forward to your next contributions.