Stripe Tokenisation Timeout with Apple Pay - ios

I'm following the tutorial here to integrate Apple Pay in a native swift app. I've completed all the steps and am currently attempting to test on a physical device.
Unfortunately the payment fails after a long wait, looking at the network traffic it looks like https://api/stripe.com/v1/tokens is timing out, Please find my code for creating an Apple Pay context below (empty strings are sensitive info that I don't want to share but are usually populated);
private func makePayment() {
let merchantIdentifier = ""
let paymentRequest = Stripe.StripeAPI.paymentRequest(withMerchantIdentifier: merchantIdentifier, country: "GB", currency: "GBP")
paymentRequest.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Payment", amount: amount),
PKPaymentSummaryItem(label: "Service Charge", amount: 0.05),
PKPaymentSummaryItem(label: "", amount: NSDecimalNumber(value: amount.doubleValue + 0.05))
]
guard let context = STPApplePayContext(paymentRequest: paymentRequest, delegate: self) else { return }
context.presentApplePay(completion: nil)
}
I have recreated the merchant ID and certificate etc. and made sure the merchant identifier matches the one on stripe.

Related

Invalid User Credentials in Paypal IOS SDK

I am getting the Invalid user credentials when i am trying to log in with paypal id. I am sure i have entered the correct client ID of the live account and its working successfully on Sandbox
PayPal SDK: Request has failed with error: invalid_user - Incorrect username/password. Please try again。 (401) |
PayPal Debug-ID: b2cedad5b6842, b2cedad5b6842 [live, PayPal iOS SDK 2.16.2] |
Details: (
{
"error_description" = "Invalid user credential";
}
).
I have entered the correct live client ID. and have made the environment to production cant get this done please help here is my code below in my app delegate:
```
//TODO: – Enter your credentials
PayPalMobile .initializeWithClientIds(forEnvironments: [PayPalEnvironmentProduction:
"**********************************-s_8AiXkLD1NA********"
])
var payPalConfig = PayPalConfiguration()
in viewDidLoad:
//=======Paypal Configuration========================================================================
// Set up payPalConfig
payPalConfig.acceptCreditCards = true
payPalConfig.merchantName = "Donation to Edhi"//Give your company name here.
payPalConfig.merchantPrivacyPolicyURL = URL(string: "“https://www.paypal.com/webapps/mpp/ua/privacy-full”")
payPalConfig.merchantUserAgreementURL = URL(string: "“https://www.paypal.com/webapps/mpp/ua/useragreement-full”")
//This is the language in which your paypal sdk will be shown to users.
payPalConfig.languageOrLocale = Locale.preferredLanguages[0]
//========== un comment line below to make paypal live==============
// environment = PayPalEnvironmentProduction
//====================================================================
//Here you can set the shipping address. You can choose either the address associated with PayPal account or different address. We’ll use .both here.
payPalConfig.payPalShippingAddressOption = .both;
This is what i have in my function
//These are the items choosen by user, for example
let item1 = PayPalItem(name: donationTypeTxt! , withQuantity: 1, withPrice:
NSDecimalNumber(string: totalPaypalAmount), withCurrency: "AUD", withSku: "don-001")
let items = [item1]
let subtotal = PayPalItem.totalPrice(forItems: items) //This is the total price of all
the items
// Optional: include payment details
let shipping = NSDecimalNumber(string: "0.00")
let tax = NSDecimalNumber(string: "0.00")
let paymentDetails = PayPalPaymentDetails(subtotal: subtotal, withShipping: shipping,
withTax: tax)
let total = subtotal.adding(shipping).adding(tax) //This is the total price including
shipping and tax
let payment = PayPalPayment(amount: total, currencyCode: "AUD", shortDescription: "3%
Merchant fee is included.", intent: .sale)
payment.items = items
payment.paymentDetails = paymentDetails
// var newamount: NSDecimalNumber = NSDecimalNumber(totalDonationAmount!) as!
NSDecimalNumber
if (payment.processable) {
let paymentViewController = PayPalPaymentViewController(payment: payment,
configuration: payPalConfig, delegate: self)
paymentViewController!.modalPresentationStyle = .fullScreen
present(paymentViewController!, animated: true, completion: nil)
}
else {
// This particular payment will always be processable. If, for
// example, the amount was negative or the shortDescription was
// empty, this payment wouldn’t be processable, and you’d want
// to handle that here.
print("Payment not processalbe: (payment)")
}
```

How to Send Bitcoin from one Wallet to Another Wallet in Swift 4

I am in the process of developing a custom Bitcoin wallet, I am able to generate the public/private keys by using Yenom/BitcoinKit. I need to send BTC to another wallet for which I am trying to use BitcoinKit. But I could not send Btc. How do I do this? can we use another Library other than BitcoinKit to send Btc from one wallet to another Wallet ?
So how do I transfer BTC from one wallet to another in Swift, please
advise.
Please check the following link
https://github.com/yenom/BitcoinKit/blob/master/Examples/Wallet/Wallet/SendViewController.swift
There is a function called sendToSomeAddress
private func sendToSomeAddress(_ amount: Int64) {
let toAddress: Address = try! AddressFactory.create("bchtest:qpytf7xczxf2mxa3gd6s30rthpts0tmtgyw8ud2sy3")
let changeAddress: Address = try! AppController.shared.wallet!.changeAddress()
var utxos: [UnspentTransaction] = []
for p in payments {
let value = p.amount
let lockScript = Script.buildPublicKeyHashOut(pubKeyHash: p.to.data)
let txHash = Data(p.txid.reversed())
let txIndex = UInt32(p.index)
print(p.txid.hex, txIndex, lockScript.hex, value)
let unspentOutput = TransactionOutput(value: value, lockingScript: lockScript)
let unspentOutpoint = TransactionOutPoint(hash: txHash, index: txIndex)
let utxo = UnspentTransaction(output: unspentOutput, outpoint: unspentOutpoint)
utxos.append(utxo)
}
let unsignedTx = createUnsignedTx(toAddress: toAddress, amount: amount, changeAddress: changeAddress, utxos: utxos)
let signedTx = signTx(unsignedTx: unsignedTx, keys: usedKeys())
peerGroup?.sendTransaction(transaction: signedTx)
}
I hope this will help

Decoding JSON in Swift

I am fetching JSON data from my server. I am using Alamofire in my code to fetch data from server.
Here's how I am decoding it:
Alamofire.request(URL_GET_DATA, method: .post).responseJSON { response in
//getting json
if let json = response.result.value {
print(json)
let newsJson : NSArray = json as! NSArray
self.parseData(data: ((newsJson[0] as AnyObject).value(forKey: "message") as? String)!)
}
}
func parseData(data : String){
//traversing through all elements of the array
let newsArray: NSArray = data as! NSArray
for i in 0..<newsArray.count{
//adding hero values to the hero list
self.newsList.append(Objectnews(
id : (newsArray[i] as AnyObject).value(forKey: "id") as? String,
heading: (newsArray[i] as AnyObject).value(forKey: "heading") as? String,
description : (newsArray[i] as AnyObject).value(forKey: "description") as? String,
time_stamp : (newsArray[i] as AnyObject).value(forKey: "time_stamp") as? String,
type : (newsArray[i] as AnyObject).value(forKey: "type") as? String,
imageurl: (newsArray[i] as AnyObject).value(forKey: "imageurl") as? String
))
}
print("reloading table")
//displaying data in tableview
self.tableView.reloadData()
}
Here's the log for same. It contains the response from server and the error it is throwing:
{
error = 0;
message = (
{
description = "September 5th marks Teacher\U2019s Day in India. It is celebrated on the birthday of our second President, Sarvepalli Radhakrishnan. It is a day when we pay respect to our teachers and appreciate their contribution to the society and our individual lives and plan special surprises, have a chance to thank them for their selfless work in making the leaders for tomorrow. N.S.S. unit celebrated Teacher's day by gifting a hand made card to each Teaching and Non-Teaching Staff of P.G.D.A.V. College. We will also like to put forward a special thanks to the creative department team of N.S.S. for their terrific job in making those beautiful hand made cards. Happy Teachers' Day to All!";
heading = "Teacher's Day Celebration";
id = 16;
imageurl = "http://check.png";
"time_stamp" = "05/09/2017 22:58";
type = News;
},
{
description = "Incessant rains and floods have brought a havoc in one of India's most populous state, Bihar due to which roads have been closed, houses destroyed and crores affected. Rahat - an initiative of Goonj NGO steps in such situations helping all those in need and this time NSS PGDAV is doing their share of help by donating Via GOONJ and is organising a Collection Drive for the flood survivors. Your donation will provide shelter, food and comfort to families. Below are some of the things you can donate to help the people:-\n\n-Tarpaulins\n-Old flex and ropes\n-Mosquito nets\n-Dry ration\n-Clothing\n-Good quality blankets \n-Wooden toiletries\n-Utensils \n-Bucket\n-Torch and batteries\n-Umbrella\n-Slippers\n-Candles\n-Solar lights etc\n\nGiving is not just about making a donation. It's about making a difference! So step forward and #DONATE.\n\nDate: 4th-9th September 2017.\nVenue- Lobby/Office Area.\nTime: 10AM-1PM.\n\nFor queries contact:\nEkta- 7503894368\nJhanvi- 7838401571";
heading = "Collection Drive for Flood Affected Areas";
id = 15;
imageurl = "http://check.png";
"time_stamp" = "02/09/2017 21:34";
type = News;
},
{
description = "\"Beauty isn't about having a pretty face, it is about having a pretty soul, a pretty heart and a pretty mind.\"\n\nN.S.S. P.G.D.A.V. is honoured and takes a great pride in telling that MS. LAXMI AGARWAL will be speaking at the orientation program of N.S.S. which is set to be held on 26th August from 12:00 P.M. onwards. Ms. Laxmi Agarwal has inspired this country by her courage and has been the recipient of International Women of Courage Award by Michelle Obama. She is an epitome of bravery.\n\nWe could not have been more proud and excited to have her encourage the students and motivate them to overcome barriers and achieve what they aim for. We are sure she will fill in positive vibes around the program and will inspire us all to do what we need to do, to achieve what we dream for, and to inspire others for the same.";
heading = "NSS Orientation ";
id = 14;
imageurl = "http://check.png";
"time_stamp" = "25/08/2017 16:47";
type = News;
},
{
description = "Welcome Fresher's,\nHere is the last step for final selection to become a member of N.S.S. Team.\nIt's the Personal Interview. So following is the list of students who have to appear on August 2, 2017\n\n\n\n\n\n\nDAY 1 - AUGUST 2, 2017\U00a0\nSLOT 1- 10:00 A.M. - 11:00 A.M.\n\n\nAmit\U00a0\nAditya Sapra\U00a0\nAman Gupta\U00a0\nAadesh Sachdeva\U00a0\nAkshay Gaba\U00a0\nAkansha Sharma\U00a0\nAnjali Kataria\U00a0\nAakash\U00a0\nAbhinav Kumar Malviya\U00a0\nAnkita Rai\U00a0\nAstha Kanojia\U00a0\nAnita Mandal\U00a0\nAnchal\U00a0\nArif\U00a0\nAaftab Ahmad\U00a0\nAshish\U00a0\nAashirya Mittal\U00a0\nAnshul Saini\U00a0\nAnanya Singh\U00a0\nAbhay Goyal\U00a0\nAnshu Kumari Gupta\U00a0\nAjay Kumar\U00a0\nAaftab\U00a0\nAnjali Bhatt\U00a0\nAditi Singh\U00a0\nAnirudh Ahlawat\U00a0\nAshutosh\U00a0\nAnuradha\U00a0\nAmiza\U00a0\nAsmat Khan\U00a0\nAyushi Chadha\U00a0\nAmbujakshi Bhardwaj\U00a0\nAnubhav jain\U00a0\nAshutosh Verma\U00a0\nAbhishek Anand\U00a0\nAbhiraj\U00a0\nAkansha\U00a0\nAbhishek ranjan\U00a0\nAyesha Chauhan\U00a0\nAkansha\U00a0\n\n\nSLOT 2 - 11:00 A.M. - 12:00 P.M.\n\n\nAnkit\U00a0\nAmar Jeet Verma\U00a0\nAnshika Adlakha\U00a0\nAnkur Verma\U00a0\nAnkita\U00a0\nAditya Raj Chaudhary\U00a0\nBhavay Virmani\U00a0\nBunty Kumar\U00a0\nBhawna\U00a0\nBronika Paul\U00a0\nBarkat Ali\U00a0\nBrahmadutt\U00a0\nBadal Sharma\U00a0\nBhavnish Sharma\U00a0\nChandra Prakash Bhambhu\U00a0\nChanchal\U00a0\nChetna Garg\U00a0\nChetan Verma\U00a0\nChirag Sethi\U00a0\nChetan\U00a0\nDeependra Pal Yadav\U00a0\nDivya Agnihotri\U00a0\nDeepak Sahni\U00a0\nDrishya Wahil\U00a0\nDiksha paut\U00a0\nDevendra Yadav\U00a0\nDivya Chabra\U00a0\nDeep Singh\U00a0\nDeepankar Vaid\U00a0\nDrishti Goyal\U00a0\nEkta Shankar\U00a0\nFarzan Iqram\U00a0\nGaurav Bhatt\U00a0\nGarima Behl\U00a0\nGaurav Saini\U00a0\nGarvish Nanda\U00a0\nGaurav Kumar\U00a0\nGarima Payla\U00a0\nGauri Dhamija\U00a0\nharshit Singh\U00a0\n\n\nSLOT 3 - 12:00 P.M. - 1:00 P.M.\n\n\U00a0\U00a0\nHimanshi Sharma\U00a0\nHarsh Gupta\U00a0\nHarshit Girdhar\U00a0\nHarsh Bansal\U00a0\nHarshita Chauhan\U00a0\nHeena\U00a0\nHeena\U00a0\nIrfan Khan\U00a0\nIshu Rai\U00a0\nJaspreet kaur\U00a0\nJyoti\U00a0\nJaisny\U00a0\nJyoti Nishad\U00a0\nKrishan Kumar\U00a0\nKrishna\U00a0\nKetu\U00a0\nKrishika Arora\U00a0\nKhushboo Yadav\U00a0\nKanan Makker\U00a0\nKriti Kapoor\U00a0\nKanika Yadav\U00a0\nKiran Pachori\U00a0\nKunal Nagar\U00a0\nKhushboo Bansal\U00a0\nKunal Sharma\U00a0\nKajal\U00a0\nLalit Mohan\U00a0\nLovely Mathur\U00a0\nMitali Baisoya\U00a0\nmanisha\U00a0\nMiti Dangwal\U00a0\nMukul Puri\U00a0\nMansingh\U00a0\nManoj Meena\U00a0\nMohammad faisal\U00a0\nM. Danish Ameer\U00a0\nMohit Jain\U00a0\nMantu Babu\U00a0";
heading = "NSS Interview Day 1";
id = 13;
imageurl = "http://check.png";
"time_stamp" = "01/08/2017 22:30";
type = News;
},
{
description = "Time and tide waits for none, we all learnt this proverb in our primary school but yesterday I experienced something contradictory to my learning. I saw the time stopping and taking a moment to absorb what was happening around? And guess what was it, it was you, the participants, the audience of Sevaarth whose overwhelming response took the event to a whole new level. You made the mighty time get adrenaline rush. \nThis year we brought in many technical advancement to our NSS unit. We launched our mobile app, website. We facilitated user with many problem solving features. We had more number of volunteers than previous year. Our reach set a new record in the history of all NSS Unit with a growth rate of more than 17,000%. As Sevaarth '17 ended in a great way, we are much more inspired by the work of every people who put their day and night in making sure you get what we have to offer. We are humbled by the response of people. \nWe owe a great deal to our sponsers - Little App, PaisaWapas, DCOP, DSB, Internsala, Nestle, SelfDrives.in, CareerLauncher, Student Stories, The Education Tree, DU Beat, Drama Cafe. Thank you to all.\nWe have a aim. We have people who craves great passion. And, these two thing is advancing us to a new level each and every day. Every day, NSS puts a positive value in this society. We are here to make a better world for each and every person out there. No matter what's your race, nationality, religion, we will make sure that you get what you deserve. In the coming years, NSS Unit of P.G.D.A.V College will get into different areas of society from education to better health care by acting as a bridge by them. \nSevaarth is an opportunity to showcase the talent of people who choose stay away from limelight in front of people. Sevaarth seemed to have touched its highest point with all the fun, the immense hard work, representing our culture from a different perspective. \nWe promise to bring you a more vibrant version of Sevaarth next year. Adios! ";
heading = "Thank you";
id = 12;
imageurl = "http://check.png";
"time_stamp" = "22/01/2017 00:22";
type = News;
}
);
}
Could not cast value of type '__NSDictionaryI' (0x106456288) to 'NSArray' (0x106455e28).
(lldb)
How can I properly decode it based on the error in the log? I am using Swift.
Follow this step :
Creat a class called APIManager
Create Delegates method like this
//MARK : Custom Protocol Methods protocol
apiManagerDelegate:NSObjectProtocol {
func apiSuccessResponse(_ response: Dictionary<String, AnyObject>)
func APIFailureResponse(_ msgError: String)
}
//MARK : Custom Extension Methods
extension apiManagerDelegate {
func apiSuccessResponse(_ response: Dictionary<String, AnyObject>){
// leaving this empty
}
func APIFailureResponse(_ msgError: String){
// leaving this empty
} }
In Your View Controller , Conforms this Delegate Methods .
Defined method like this to consume web service in API Manager
func signUpAPI(firstName : String, lastName:String, email:String, password:String, confirmPwd:String, mobile:String, age:String, gender:String, signUp_type:Int) {
//Payload Dict
let payloadDict = [
"first_name" : firstName,
"last_name" : lastName,
"email" : email,
....
] as [String : Any]
//Showing activity indicator
---progressbar goes here
//Call Web API using Alamofire library
AlamoFireSharedManagerInit()
Alamofire.request(HCConstants.URL.HC_BASEURL + HCConstants.URL.SIGNUP, method: .post, parameters: payloadDict, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
do
{
//Checking For Error
if let error = response.result.error {
//Call failure delegate method
print(error)
//Stop AcitivityIndicator
self.hideHud()
self.delegate?.APIFailureResponse("Something goes wrong , Try after some time!!")
return
}
//Store Response
let responseValue = try JSONSerialization.jsonObject(with: response.data!, options: JSONSerialization.ReadingOptions()) as! Dictionary<String, AnyObject>
print(responseValue)
//Check Success Flag
print(responseValue["success"] as! Bool)
if let mSuccessFlag = responseValue["success"] as? Bool {
//Failure message
if !mSuccessFlag {
self.delegate?.APIFailureResponse(responseValue["message"] as! String? ?? "Something goes wrong , Please try after some time")
}
//Call success delegate method
else {
self.delegate?.apiSuccessResponse(responseValue)
}
}
//Stop AcitivityIndicator
self.hideHud()
} catch {print("Sign up API fired exception")}
}
}
Above method parse the data and send it to the success or failure method to your viewcontroller and from there you need to populate the data and just render it .
Isn't it super easy ?

PKPaymentAuthorizationViewController(paymentRequest: requestObject) is returning nil

I am facing a problem in initilizing PKPaymentAuthorizationViewController returning nil in one of the device.
The device region is set to UK and I have added a UK issued card in the Apple Wallet.
The PKPaymentRequest is configured as following:
let request = PKPaymentRequest()
request.merchantIdentifier = "mymerchantid"
request.supportedNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex]
request.merchantCapabilities = PKMerchantCapability.Capability3DS
request.countryCode = "US"
request.currencyCode = "USD"
let price: <NSDecimalNumber>
let item : PKPaymentSummaryItem = PKPaymentSummaryItem(label: "amount", amount: price, type: .Pending)
request.paymentSummaryItems = [
item
]
let paymentAuthorizationVC = PKPaymentAuthorizationViewController(paymentRequest: request) // Returning Nil
if PKPaymentAuthorizationViewController.canMakePaymentsUsingNetworks(SupportedPaymentNetworks) // Returns true
Device: iPhone 6
OS: 10.2.2
Note: Same Card is onboared in another device for the same App its working fine.
Tried as mentioned in the below link and few other blogs- no luck
Apple pay PKPaymentauthorizationViewController always returning nil when loaded with Payment request
Looking for suggestions.
I had this same problem and the cause was using a Discover card for testing when it's not included as a supported payment network. Make sure that you are passing in all the credit card types that your user base will possibly use.
Try changing this line:
request.supportedNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex]
To the following:
request.supportedNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex, PKPaymentNetwork.discover]
In Swift3, The declaration for PKPaymentAuthorizationViewController init() is not defined as optional, even though it does return nil when it fails.

CLGeocoder returns wrong results when city name is equal to some country's name (and not only)

In one of my apps I need to add an ability to find a city by its name. I am using CLGeocoder to achieve this and I want it to have a behaviour identical to iOS weather app.
Below is the code which I have:
CLGeocoder().geocodeAddressString(searchBar.text!, completionHandler:{ (placemarks, error) -> Void in
guard let nonNilMarks = placemarks else {return}
for placemark in nonNilMarks {
print("locality: \(placemark.locality)")
print("name: \(placemark.name)")
print("country: \(placemark.country)")
print("formatted address: \(placemark.addressDictionary)")
}
})
It works very well in most cases. However, I recently noticed some cases when it fails. Below is the output for some examples:
Searching for 'Milan' - WORKS
locality: Optional("Milan")
name: Optional("Milan")
country: Optional("Italy")
formatted address: Optional([SubAdministrativeArea: Milan, State: Lombardy, CountryCode: IT, Country: Italy, Name: Milan, FormattedAddressLines: (
Milan,
Italy
), City: Milan])
This is the correct output
Searching for 'Italy, TX' - WORKS
There is a town in Texas called Italy. If I type 'Italy, TX' the output is:
locality: Optional("Italy")
name: Optional("Italy")
country: Optional("United States")
formatted address: Optional([SubAdministrativeArea: Ellis, State: TX, CountryCode: US, Country: United States, Name: Italy, FormattedAddressLines: (
"Italy, TX",
"United States"
), City: Italy])
Searching for 'Italy' - FAILS
When I type just 'Italy' I only get place mark for the country:
locality: nil
name: Optional("Italy")
country: Optional("Italy")
formatted address: Optional([CountryCode: IT, Name: Italy, FormattedAddressLines: (
Italy
), Country: Italy])
Searching for 'Singapore, Singapore' - WORKS
This is similar to the case with 'Italy, TX':
locality: Optional("Singapore")
name: Optional("Singapore")
country: Optional("Singapore")
formatted address: Optional([City: Singapore, CountryCode: SG, Name: Singapore, State: Singapore, FormattedAddressLines: (
Singapore,
Singapore
), Country: Singapore])
Searching for 'Singapore' - FAILS
Again, seems similar to the case with 'Italy'. It only finds a country:
locality: nil
name: Optional("Singapore")
country: Optional("Singapore")
formatted address: Optional([CountryCode: SG, Name: Singapore, FormattedAddressLines: (
Singapore
), Country: Singapore])
Preliminary guess
At this stage I though that maybe geocodeAddressString: stops searching if it finds a country with the name equal to the search parameter, so I tried changing my code to :
let addrDict = [kABPersonAddressCityKey as NSString: searchBar.text!]
CLGeocoder().geocodeAddressDictionary(addrDict, completionHandler:{ (placemarks, error) -> Void in
print(placemarks)
})
I thought that by restricting the search term to the city name I would get correct results. Unfortunately, I get the exact same behaviour!
And THEN I realised that I have problems not only with cases when city name is equal to the country name.
Searching for 'Tokyo' - EPIC FAIL
locality: nil
name: Optional("Tokyo")
country: Optional("Japan")
formatted address: Optional([CountryCode: JP, Name: Tokyo, State: Tokyo, FormattedAddressLines: (
Tokyo,
Japan
), Country: Japan])
Conclusion
Not only can CLGeocoder omit results (like in the case of 'Italy') but it can also tell me that a place does not have a locality when, in fact, it does (I believe last time I checked a map Tokyo was still a city!).
Does anyone know how I can resolve any of these issues?
Weather app does it somehow - searching for 'Singapore' or 'Italy' there gives correct results. I will be grateful for any help!
P.S. Although I am using Swift I am adding Objective-C as a tag as I think that this question is not Swift specific.
Usage what you showed is completely right and I don't think there is anything else you can do to improve results. It is still just some complicated algorithm that tries to sort results based on set of rules and some assumption.
That being sad, I understand your frustration completely because I've been there and done that. The problem is that Geocoding database is not obviously complete and Apple is not the company who leads this field - Google is. Here you can see technical note from when the Geocoder was introduced saying that there are still countries that are not supported, or just partially supported.
So my suggestion to you is that if you want to get best results (though still not fail-proof), switch to Google Geolocation. For quite great amount of requests it is free and after that it costs some very minor amounts. The success rate is around 99% for all the basic searches from what I experienced and it only gets better if you provide more information. The API options are also quite extensive.
Here are links for developer documentation for both Geocoding and Reverse Geocoding:
https://developers.google.com/maps/documentation/geocoding/intro
https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse
Hope it helped at least a little.
EDIT: After I wrote this I did a little research and it seems that I am not the only person to make this claim (also including the same unsupported link).
CLGeocoder requests are rate limited and if the app goes over the threshold, further requests may not be fulfilled. CLGeocoder requires network connection which may be limiting under some circumstances and the response from the server is not always instant. If you do not insist on CLGeocoder, local database might give you more flexibility and possibly better user experience.
Take a look at the cities???.zip on GeoNames, for an alternative solution where you would import the data to a local database.
You can also do this by google API like this
//chakshu
var urlString = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=\(searchString)&sensor=true&key=\(Google_Browser_Key)"
var linkUrl:NSURL = NSURL(string:urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)!
if(countElements(urlString)>0 && !urlString.isEmpty)
{
// if let fileData = String(contentsOfURL: NSURL(string: urlString)!, encoding: NSUTF8StringEncoding, error: nil)
if let fileData = String(contentsOfURL: linkUrl, encoding: NSUTF8StringEncoding, error: nil)
{
println(fileData)
var data = fileData.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
var localError: NSError?
if(data != nil)
{
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError)
}
}
}
I was facing this problem too here on Brazil, só I made a terrible solution for that:
public func getLatLonFrom(address: String, completion:#escaping ((CLLocation?, NSError?)->Void)) {
//LCEssentials.printInfo(title: "LOCATION", msg: "CEP: \(address)")
let geoCoder = CLGeocoder()
let params: [String: Any] = [
CNPostalAddressPostalCodeKey: address,
CNPostalAddressISOCountryCodeKey: "BR"
]
geoCoder.geocodeAddressString(address) { (placemarks, error) in
//LCEssentials.printInfo(title: "LOCATION", msg: "PLACEMARKS FIRST: \(placemarks?.debugDescription)")
if let locais = placemarks {
guard let location = locais.first?.location else {
let error = NSError(domain: LCEssentials().DEFAULT_ERROR_DOMAIN, code: LCEssentials().DEFAULT_ERROR_CODE, userInfo: [ NSLocalizedDescriptionKey: "Address not found" ])
completion(nil, error)
return
}
completion(location, nil)
}else{
geoCoder.geocodeAddressDictionary(params) { (placemarks, error) in
//LCEssentials.printInfo(title: "LOCATION", msg: "PLACEMARKS: \(placemarks?.debugDescription)")
guard let founded = placemarks, let location = founded.first?.location else {
let error = NSError(domain: LCEssentials().DEFAULT_ERROR_DOMAIN, code: LCEssentials().DEFAULT_ERROR_CODE, userInfo: [ NSLocalizedDescriptionKey: "Address not found" ])
completion(nil, error)
return
}
completion(location, nil)
}
}
}
}
I force the Country Code to BR ( Brazil ) and then i can find the address by ZIP CODE. If it return NIL for placemarks on geocodeAddressString then i call the geocodeAddressDictionary and i receive the correct result.
This solution can cover major zip code from BR. It is a mess code, but for now it works.
Future projects i will use Google Maps.

Resources