Swift 2.1 Paytm Integration Issue - uiviewcontroller

I am facing this kind of error: 'PGTransactionViewController' has no member 'initTransactionForOrder'. Can anyone help me out to sort out it.
func Pay_btn_Action(sender:UIButton!) {
var mc: PGMerchantConfiguration = PGMerchantConfiguration.defaultConfiguration()
mc.checksumGenerationURL = "https://pguat.paytm.com/paytmchecksum/paytmCheckSumGenerator.jsp"
mc.checksumValidationURL = "https://pguat.paytm.com/paytmchecksum/paytmCheckSumVerify.jsp"
var orderDict: [NSObject : AnyObject] = NSMutableDictionary() as [NSObject : AnyObject]
orderDict["MID"] = "WorldP64425807474247"
orderDict["CHANNEL_ID"] = "WAP"
orderDict["INDUSTRY_TYPE_ID"] = "Retail"
orderDict["WEBSITE"] = "worldpressplg"
orderDict["TXN_AMOUNT"] = "1"
orderDict["ORDER_ID"] = PaymentView.generateOrderIDWithPrefix("")
orderDict["REQUEST_TYPE"] = "DEFAULT"
orderDict["CUST_ID"] = "1234567890"
var order: PGOrder = PGOrder(params: orderDict)
PGServerEnvironment.selectServerDialog(self.tbl_Payment, completionHandler: {(type: ServerType) -> Void in
var txnController: PGTransactionViewController = PGTransactionViewController.initTransactionForOrder(order)
if type != eServerTypeNone {
txnController.serverType = type
txnController.merchant = mc
txnController.delegate = self
self.showController(txnController)
}
})
}

I don't know this specific library, but in general, if this has been adapted to Swift from Objective-C, it should be something like this:
PGTransactionViewController(transactionForOrder: order)

I have solved all the queries.
func Pay_btn_Action(sender:UIButton!) {
//Step 1: Create a default merchant config object
let mc: PGMerchantConfiguration =
PGMerchantConfiguration.defaultConfiguration()
//Step 2: If you have your own checksum generation and validation url set this here. Otherwise use the default Paytm urls
mc.checksumGenerationURL = "https://pguat.paytm.com/paytmchecksum/paytmCheckSumGenerator.jsp"
mc.checksumValidationURL = "https://pguat.paytm.com/paytmchecksum/paytmCheckSumVerify.jsp"
//Step 3: Create the order with whatever params you want to add. But make sure that you include the merchant mandatory params
var orderDict: [NSObject : AnyObject] = NSMutableDictionary() as [NSObject : AnyObject]
orderDict["MID"] = "WorldP64425807474247"
//Merchant configuration in the order object
orderDict["CHANNEL_ID"] = "WAP"
orderDict["INDUSTRY_TYPE_ID"] = "Retail"
orderDict["WEBSITE"] = "worldpressplg"
//Order configuration in the order object
orderDict["TXN_AMOUNT"] = "5"
orderDict["ORDER_ID"] = ViewController.generateOrderIDWithPrefix("")
orderDict["REQUEST_TYPE"] = "DEFAULT"
orderDict["CUST_ID"] = "1234567890"
let order: PGOrder = PGOrder(params: orderDict)
//Step 4: Choose the PG server. In your production build dont call selectServerDialog. Just create a instance of the
//PGTransactionViewController and set the serverType to eServerTypeProduction
PGServerEnvironment.selectServerDialog(self.view, completionHandler: {(type: ServerType) -> Void in
let txnController = PGTransactionViewController.init(transactionForOrder: order)
if type != eServerTypeNone {
txnController.serverType = type
txnController.merchant = mc
txnController.delegate = self
self.showController(txnController)
}
})
}
If anyone wants the Swift 2.1 Paytm wallet Integration code into their iOS app can download the whole project from here.
link

Related

Handling 2 keys for same value in single class

I have a use case in which I get score form JSON using
let score = json["score_test"].arrayValue.map {Score.decode(json: $0)}
I have to reuse this class for a response in which only key for the value changes i.e
let score = json["score"].arrayValue.map {Score.decode(json: $0)}
Is there a way to achieve this so that I get the data of Score object whether the key is score_test or score depending on the JSON using the same class?
Also I tried using nil check but since the object is initialized that is not working.
Model of Score:
class Score: Object, Decoder {
dynamic var id: String = ""
dynamic var title: String = ""
dynamic var body: String = ""
dynamic var cardOrder: Int = 0
dynamic var video: Video? = nil
override static func primaryKey() -> String? {
return "id"
}
typealias T = Score
// MARK: Decoder method
static func decode(json: JSON) -> Score {
let id = json["_id"].stringValue
let title = json["title"].stringValue
let body = json["data"].stringValue
let cardOrder = json["card_order"].intValue
var video: Video?
if (json["video"].exists()) {
video = Video.decode(json: json["video"])
}
let score = Score()
score.id = id
score.title = title
score.body = body
score.video = video
score.cardOrder = cardOrder
return score
}
}
From what I understand, score is of type [Score] so what I'd do is:
var score = json["score_test"].arrayValue.map {Score.decode(json: $0)}
if score.isEmpty {
score = json["score"].arrayValue.map {Score.decode(json: $0)}
}

Create new Realm List and add items

I make a API request with Alamofire , I then get a response in JSON format, I then parse the JSON into a NSDictionary to get to the data I want.
The data I get is four Arrays of different items.
I want to the create a new List in Realm to save these items in.
Here are my Realm Object Classes :
class ListOfDefinitions: Object {
let listOfItems = List<Item>()
}
and
class Item: Object {
dynamic var AverageCost = Int()
dynamic var Barcode = ""
dynamic var Description = ""
dynamic var InternalUnique = Int()
dynamic var LastCost = Int()
dynamic var LimitToMainRegionUnique = Int()
dynamic var Notes = ""
dynamic var StockCategoryUnique = Int()
dynamic var StockCode = ""
dynamic var StockGroupUnique = Int()
dynamic var UnitDescriptor = ""
}
Here is my code on how I handle the JSON response and where I want to save the data in my code.
var newItemInStockList : ListOfDefinitions! // declared in the class
let newItemInStock = Item()
.responseJSON { response in
switch response.result {
case .Success(let JSON):
// print("Success with JSON: \(JSON)")
let response = JSON as! NSDictionary
let responseParams = response.objectForKey("ResponseParameters") as! NSDictionary
//print(responseParams)
//let stockItemGroupList = responseParams.objectForKey("StockItemGroupList")
let stockItemList = responseParams.objectForKey("StockItemList") as! NSDictionary
//print(stockItemList)
let listofDefinitions = stockItemList.objectForKey("ListofDefinitions") as! NSArray
print(listofDefinitions.count)
for defJson in listofDefinitions {
print(defJson["Description"])
someString = defJson["Description"] as! String
print(someString)
// Because there are 4 arrays of items this for loop will be red 4 times, each time it is red I want o create a new list and add the items to the list
// This comment area is where I tried to create a new list and then .append the items in it, but it doesn't work.
// let newOne = ListOfDefinitions()
//
//
// try! realm.write{
//
// realm.add(newOne)
// }
// self.newItemInStock.AverageCost = defJson["AverageCost"] as! Int
// self.newItemInStock.Barcode = defJson["Barcode"] as! String
// self.newItemInStock.Description = defJson["Description"] as! String
// self.newItemInStock.InternalUnique = defJson["InternalUnique"] as! Int
// self.newItemInStock.LastCost = defJson["LastCost"] as! Int
// self.newItemInStock.LimitToMainRegionUnique = defJson["LimitToMainRegionUnique"] as! Int
// self.newItemInStock.Notes = defJson["Notes"] as! String
// self.newItemInStock.StockCategoryUnique = defJson["StockCategoryUnique"] as! Int
// self.newItemInStock.StockCode = defJson["StockCode"] as! String
// self.newItemInStock.StockGroupUnique = defJson["StockGroupUnique"] as! Int
// self.newItemInStock.UnitDescriptor = defJson["UnitDescriptor"] as! String
//
// try! realm.write{
//
// self.newItemInStockList.listOfItems.append(self.newItemInStock)
// }
}
case .Failure(let error):
print("Request failed with error: \(error)")
}
And here is what I get when I print the 4 Arrays
Looking at your sample code, I think the main issue happening here is that you're re-using the same self.newItemInStock instance for each object you're adding to the list.
It would be best to create a new Item object in the loop as you're going along and append that to the List object.
I recommend using a combination of AlamofireObjectMapper to handle all your JSON mapping (both ways) https://github.com/tristanhimmelman/AlamofireObjectMapper
and the ListTransform found in ObjectMapper+Realm https://github.com/Jakenberg/ObjectMapper-Realm
They're both available to be installed through cocoapods. Your code will look much cleaner and easier to maintain

iOS Hyper Sync More Than One-toMany Relationsship to the Same Object

I am making an app that connects to the TMDB API.
I use Hyper Sync to persist JSON to Core Data with the following code:
let completion = { (error: NSError?) in
if error == nil {
self.backdropData = [[String: AnyObject]]()
for image in movie.backdrops!.allObjects as! [Image] {
var data = [String: AnyObject]()
data[ThumbnailTableViewCell.Keys.ID] = image.filePath as String!
data[ThumbnailTableViewCell.Keys.OID] = image.objectID
if let filePath = image.filePath {
let url = "\(Constants.TMDB.ImageURL)/\(Constants.TMDB.BackdropSizes[0])\(filePath)"
data[ThumbnailTableViewCell.Keys.URL] = url
}
self.backdropData!.append(data)
}
self.posterData = [[String: AnyObject]]()
for image in movie.posters!.allObjects as! [Image] {
var data = [String: AnyObject]()
data[ThumbnailTableViewCell.Keys.ID] = image.filePath as String!
data[ThumbnailTableViewCell.Keys.OID] = image.objectID
if let filePath = image.filePath {
let url = "\(Constants.TMDB.ImageURL)/\(Constants.TMDB.BackdropSizes[0])\(filePath)"
data[ThumbnailTableViewCell.Keys.URL] = url
}
self.posterData!.append(data)
}
self.tableView.reloadData()
}
}
var data = [[String: AnyObject]]()
data.append(["id": movie.movieID!.integerValue,
"backdrops": backdrops,
"posters": posters])
let predicate = NSPredicate(format: "movieID=%# ", movie.movieID!)
Sync.changes(data, inEntityNamed: "Movie", predicate: predicate, dataStack: appDelegate.dataStack, completion: completion)
When Sync finished saving the JSON data, the backdrops are deleted and only the posters are saved in Core Data. This is not the behavior I wanted. I also want to save the backdrops in Core Data. Any way to fix this?
Here is the screenshot of my Core Data model:
For full source code, here is the link to my Github project:
Cineko

Swift - Crash when try to get JSON values for second time

I am trying to get an array of values from a JSON file using Swift. I found the way to get the values printed when a button is pressed using a IBAction method.
The Function is printing the array fine the first time the button is pressed however, if I press the button again the app crashes giving the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
The array that I get the first time from printing jsonResult looks Like:
1: {
Age = 30;
Email = "info#example.com";
Location = Rome;
MyText = "Design Agency";
Name = Admin;
Password = 123456;
REF = 002;
"Reg_Date" = "2015-07-28";
Sex = Male;
Surname = "Mobile App"; }
2: {
Age = 30;
Email = "example#gmail.com";
Location = London;
MyText = "aaaaaaaaa";
Name = Andrew;
Password = 123456;
REF = 001;
"Reg_Date" = "2015-07-28";
Sex = Male;
Surname = Nos; }
It seems that the second time I call the function, it cannot read the file anymore.
Whats wrong with my code? Do I need to close the connection?
#IBAction func login_button(sender: AnyObject) {
searchFunction()
}
func searchFunction() {
var tempUrlValue = loginJsonResults.stringForKey("loginJsonResults")
let urlPath: String = "https://example.com/iOS/users_result.json"
var url: NSURL = NSURL(string: urlPath)!
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
connection.start()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
self.data.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
var err: NSError
var jsonResult: NSMutableArray = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSMutableArray
//Call jsonResult Values
var temporaryString: AnyObject = jsonResult[1]
for (index, jsonResult) in enumerate(jsonResult){
println("\(index + 1): \(jsonResult)")
countUsers++
}
println(countUsers)
}

Best way to convert JSON or other untyped data into typed classes in Swift?

I'm trying to parse out JSON into typed classes for safety/convenience, but it's proving very clunky. I wasn't able to find a library or even a post for Swift (Jastor is as close as I got). Here's a fabricated little snippet to illustrate:
// From NSJSONSerialization or similar and casted to an appropriate toplevel type (e.g. Dictionary).
var parsedJson: Dictionary<String, AnyObject> = [ "int" : 1, "nested" : [ "bool" : true ] ]
class TypedObject {
let stringValueWithDefault: String = ""
let intValueRequired: Int
let nestedBoolBroughtToTopLevel: Bool = false
let combinedIntRequired: Int
init(fromParsedJson json: NSDictionary) {
if let parsedStringValue = json["string"] as? String {
self.stringValueWithDefault = parsedStringValue
}
if let parsedIntValue = json["int"] as? Int {
self.intValueRequired = parsedIntValue
} else {
// Raise an exception...?
}
// Optional-chaining is actually pretty nice for this; it keeps the blocks from nesting absurdly.
if let parsedBool = json["nested"]?["bool"] as? Bool {
self.nestedBoolBroughtToTopLevel = parsedBool
}
if let parsedFirstInt = json["firstInt"] as? Int {
if let parsedSecondInt = json["secondInt"] as? Int {
self.combinedIntRequired = parsedFirstInt * parsedSecondInt
}
}
// Most succinct way to error if we weren't able to construct self.combinedIntRequired?
}
}
TypedObject(fromParsedJson: parsedJson)
There's a number of issues here that I'm hoping to work around:
It's extremely verbose, since I need to wrap every single property in a copy-pasted if-let for safety.
I'm not sure how to communicate errors when required properties are missing (as noted above). Swift seems to prefer (?) using exceptions for show-stopping problems (rather than pedestrian malformed data as here).
I don't know a nice way to deal with properties that exist but are the wrong type (given that the as? casting will fail and simply skip the block, it's not very informative to the user).
If I want to translate a few properties into a single one, I need to nest the let blocks proportional to the number of properties I'm combining. (This is probably more generally a problem with combining multiple optionals into one value safely).
In general, I'm writing imperative parsing logic when I feel like I ought to be able to do something a little more declarative (either with some stated JSON schema or at least inferring the schema from the class definition).
I do this using the Jastor framework:
1) Implement a Protocol that has a single function that returns an NSDictionary response:
protocol APIProtocol {
func didReceiveResponse(results: NSDictionary)
}
2) Create an API class that defines an NSURLConnection object that can be used as a Request URL for iOS's networking API. This class is created to simply return a payload from the itunes.apple.com API.
class API: NSObject {
var data: NSMutableData = NSMutableData()
var delegate: APIProtocol?
func searchItunesFor(searchTerm: String) {
// Clean up the search terms by replacing spaces with +
var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+",
options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music"
var url: NSURL = NSURL(string: urlPath)
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)
println("Search iTunes API at URL \(url)")
connection.start()
}
// NSURLConnection Connection failed.
func connection(connection: NSURLConnection!, didFailWithError error: NSError!) {
println("Failed with error:\(error.localizedDescription)")
}
// New request so we need to clear the data object.
func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
self.data = NSMutableData()
}
// Append incoming data.
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
self.data.appendData(data)
}
// NSURLConnection delegate function.
func connectionDidFinishLoading(connection: NSURLConnection!) {
// Finished receiving data and convert it to a JSON object.
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data,
options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
delegate?.didReceiveResponse(jsonResult)
}
}
3) Create a class with associated properties that inherits from Jastor
NSDictionary response:
{
"resultCount" : 50,
"results" : [
{
"collectionExplicitness" : "notExplicit",
"discCount" : 1,
"artworkUrl60" : "http:\/\/a4.mzstatic.com\/us\/r30\/Features\/2a\/b7\/da\/dj.kkirmfzh.60x60-50.jpg",
"collectionCensoredName" : "Changes in Latitudes, Changes in Attitudes (Ultmate Master Disk Gold CD Reissue)"
}
]
}
Music.swift
class Music : Jastor {
var resultCount: NSNumber = 0
}
4) Then in your ViewController be sure to set the delegate to self and then make a call to the API's searchITunesFor() method.
var api: API = API()
override func viewDidLoad() {
api.delegate = self;
api.searchItunesFor("Led Zeppelin")
}
5) Implement the Delegate method for didReceiveResponse(). Jastor extends your class to set a NSDictionary of the results returned from the iTunes API.
// #pragma - API Delegates
func didReceiveResponse(results: NSDictionary) {
let music = Music(dictionary: results)
println(music)
}
Short version: Since init isn't allowed to fail, validation has to happen outside of it. Optionals seem to be the intended tool for flow control in these cases. My solution is to use a factory method that returns an optional of the class, and use option chaining inside it to extract and validate the fields.
Note also that Int and Bool aren't children of AnyObject; data coming from an NSDictionary will have them stored as NSNumbers, which can't be cast directly to Swift types. Thus the calls to .integerValue and .boolValue.
Long version:
// Start with NSDictionary since that's what NSJSONSerialization will give us
var invalidJson: NSDictionary = [ "int" : 1, "nested" : [ "bool" : true ] ]
var validJson: NSDictionary = [
"int" : 1,
"nested" : [ "bool" : true ],
"firstInt" : 3,
"secondInt" : 5
]
class TypedObject {
let stringValueWithDefault: String = ""
let intValueRequired: Int
let nestedBoolBroughtToTopLevel: Bool = false
let combinedIntRequired: Int
init(intValue: Int, combinedInt: Int, stringValue: String?, nestedBool: Bool?) {
self.intValueRequired = intValue
self.combinedIntRequired = combinedInt
// Use Optionals for the non-required parameters so
// we know whether to leave the default values in place
if let s = stringValue {
self.stringValueWithDefault = s
}
if let n = nestedBool {
self.nestedBoolBroughtToTopLevel = n
}
}
class func createFromDictionary(json: Dictionary<String, AnyObject>) -> TypedObject? {
// Validate required fields
var intValue: Int
if let x = (json["int"]? as? NSNumber)?.integerValue {
intValue = x
} else {
return nil
}
var combinedInt: Int
let firstInt = (json["firstInt"]? as? NSNumber)?.integerValue
let secondInt = (json["secondInt"]? as? NSNumber)?.integerValue
switch (firstInt, secondInt) {
case (.Some(let first), .Some(let second)):
combinedInt = first * second
default:
return nil
}
// Extract optional fields
// For some reason the compiler didn't like casting from AnyObject to String directly
let stringValue = json["string"]? as? NSString as? String
let nestedBool = (json["nested"]?["bool"]? as? NSNumber)?.boolValue
return TypedObject(intValue: intValue, combinedInt: combinedInt, stringValue: stringValue, nestedBool: nestedBool)
}
class func createFromDictionary(json: NSDictionary) -> TypedObject? {
// Manually doing this cast since it works, and the only thing Apple's docs
// currently say about bridging Cocoa and Dictionaries is "Information forthcoming"
return TypedObject.createFromDictionary(json as Dictionary<String, AnyObject>)
}
}
TypedObject.createFromDictionary(invalidJson) // nil
TypedObject.createFromDictionary(validJson) // it works!
I've also done the following to convert to/from:
class Image {
var _id = String()
var title = String()
var subTitle = String()
var imageId = String()
func toDictionary(dict dictionary: NSDictionary) {
self._id = dictionary["_id"] as String
self.title = dictionary["title"] as String
self.subTitle = dictionary["subTitle"] as String
self.imageId = dictionary["imageId"] as String
}
func safeSet(d: NSMutableDictionary, k: String, v: String) {
if (v != nil) {
d[k] = v
}
}
func toDictionary() -> NSDictionary {
let jsonable = NSMutableDictionary()
self.safeSet(jsonable, k: "title", v: self.title);
self.safeSet(jsonable, k: "subTitle", v: self.subTitle);
self.safeSet(jsonable, k: "imageId", v: self.imageId);
return jsonable
}
}
Then I simply do the following:
// data (from service)
let responseArray = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSArray
self.objects = NSMutableArray()
for item: AnyObject in responseArray {
var image = Image()
image.toDictionary(dict: item as NSDictionary)
self.objects.addObject(image)
}
If you want to POST the data:
var image = Image()
image.title = "title"
image.subTitle = "subTitle"
image.imageId = "imageId"
let data = NSJSONSerialization.dataWithJSONObject(image.toDictionary(), options: .PrettyPrinted, error: nil) as NSData
// data (to service)
request.HTTPBody = data;