Remove part of google drive string URL - ios

I have the string below and I would like to remove this part "https://drive.google.com/open?id=" so that my string only has "1FN7S3N_9IAkWYMjLnqh4BKsh8_YT0Zma" Any suggestions? Thanks!
let string = "https://drive.google.com/open?id=1FN7S3N_9IAkWYMjLnqh4BKsh8_YT0Zma"

URL could have other parameters so just replacing string might not be a good solution. URLComponents comes in handy for this.
func getQueryStringParameter(url: String, param: String) -> String? {
return URLComponents(string: url)?.queryItems?.first{ $0.name == param }?.value
}
And use it like this.
let string = "https://drive.google.com/open?id=1FN7S3N_9IAkWYMjLnqh4BKsh8_YT0Zma"
if let id = getQueryStringParameter(url: string, param: "id") {
print(id)
}

Get 2nd component separated by google drive part:
let string = "https://drive.google.com/open?id=1FN7S3N_9IAkWYMjLnqh4BKsh8_YT0Zma"
let id = string.components(separatedBy: "https://drive.google.com/open?id=")[1]
Replace google drive part with empty string:
let string = "https://drive.google.com/open?id=1FN7S3N_9IAkWYMjLnqh4BKsh8_YT0Zma"
let id = string.replacingOccurrences(of: "https://drive.google.com/open?id=", with: "")

Related

Creating a struct that conforms to the encodable protocol gives me an error due to a timestamp being a variable. Is there a way to fix this?

import Firebase
import UIKit
//I followed the information you gave me. I am unsure if I have done that correctly or as you were expecting it. But, it gives the same error for codable. "Type post doesn't conform to protocol decodable".
import Firebase
import UIKit
struct Post: Codable {
var caption: String
var likes: Int
var imageUrl: String
var ownerUid: String
var postId: String
var ownerImageUrl: String
var ownerUsername: String
var didLike = false
var hashtags: [String]
var activity: [String]
var video: String
var videoURL: URL
var videoFileExtension: String?
var music: String
private var timestampDate: Date
var timestamp: Timestamp { Timestamp(date: timestampDate) }?
enum CodingKeys: String, CodingKey {
case caption
case likes
case imageUrl
case ownerUid
case timestamp
case postId
case ownerImageUrl
case ownerUsername
case didLike
case hashtags
case activity
case video
case videoURL
case videoFileExtension
case music
}
init(postId: String, dictionary: [String: Any]) {
self.postId = dictionary["postId"] as? String ?? ""
self.caption = dictionary["caption"] as? String ?? ""
self.likes = dictionary["likes"] as? Int ?? 0
self.imageUrl = dictionary["imageUrl"] as? String ?? ""
self.ownerUid = dictionary["ownerUid"] as? String ?? ""
self.ownerImageUrl = dictionary["ownerImageUrl"] as? String ?? ""
self.ownerUsername = dictionary["ownerUsername"] as? String ?? ""
self.hashtags = dictionary["hashtags"] as? [String] ?? [String]()
self.activity = dictionary["activity"] as? [String] ?? [String]()
self.video = dictionary["video"] as? String ?? ""
self.videoURL = dictionary["videoURL"] as? URL ?? URL(fileURLWithPath: "")
self.music = dictionary["music"] as? String ?? ""
if let asDouble = dictionary["timestamp"] as? Double { self.timestampDate = Date(timeIntervalSince1970: asDouble) } else { self.timestampDate = Date() }
}
//Here I am using JSONEncoder to be called in other parts of the code and to //help process the data to firebase
var dictionary: [String: Any] {
let data = (try? JSONEncoder().encode(self)) ?? Data()
return (try? JSONSerialization.jsonObject(with: data, options: [.mutableContainers, .allowFragments]) as? [String: Any]) ?? [:]
}
}
The compiler will not synthesize Codable for you since you have a coding key for a computed property. This is not supported, auto synthesis only works with stored properties. If you remove timestamp from your CodingKeys enum it should work fine, but your encoded JSON won’t contain the timestamp. If you need that in your output or parse it from input you will have to implement Codable yourself.
Upon the initial question:
A way to do that would be to keep the Date as private, and use Timestamp as a computed value:
private var timestampDate: Date
var timestamp: Timestamp { Timestamp(date: timestampDate) }
This need a little changes in the CodingKeys, because timestamp doesn't exists for it, but timestampDate does now:
enum CodingKeys: String, CodingKey {
...
case timestampDate = "timestamp"
}
Now, there are still a few issues.
self.videoURL = dictionary["videoURL"] as? URL ?? URL(fileURLWithPath: "")
This shouldn't work, since you are getting JSON, and URL isn't really a JSON value.
Instead:
let videoURLString = dictionary["videoURL"] as? String ?? ""
self.videoURL = URL(fileURLWithPath: videoURLString)
Now, you might have an issue with the Date value, you need to tell the encoder what's the logic:
var dictionary: [String: Any] {
do {
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .secondsSince1970
let data = try encoder.encode(self)
let dict = try JSONSerialization.jsonObject(with: data)
return dict as? [String: Any] ?? [:]
} catch {
print("Error: \(error)")
return [:]
}
}
I used as reference date 1970, depending on your settings, you might change it when encoding or decoding.
Also, I did proper do/try/catch, please don't write try?. If there is an error, you won't see it, you are just ignoring them.
Now, it's unrelated, but in the init(postId:dictionary:) you don't read postId value. Did you meant self.postId = dictionary["postId"] as? String ?? postId ?
Instead of using dictionary["someValue"], why not use dictionary[CodingKeys.someValue.rawValue], avoiding you any typo error?

How can I create a UITableView for each property in a model?

I have a struct that looks something like this:
internal class RemoteProfileModel: Decodable {
let userId: String
let company: String
let email: String
let firstName: String
let lastName: String
let department: String
let jobTitle: String
let pictureUri: URL?
let headerUri: URL?
let bio: String
let updatedDate: Date
}
I need to list out these properties in a UITableView. I also need to use different cell types for some of the properties.
I'm thinking perhaps I should convert this struct to a dictionary of key/value pairs, and use the key to determine the cell type.
Is this possible? Is there another way to achieve this? I am unsure if it possible to convert a struct to a dictionary so am not sure this is the best way?
to convert a class to a dictionary,
class RemoteProfileModel: Decodable {
let userId: String
let company: String
let email: String
let firstName: String
let lastName: String
let department: String
let jobTitle: String
let pictureUri: URL?
let headerUri: URL?
let bio: String
let updatedDate: Date
init() {
userId = "666"
company = "AAPL"
email = "hehe#163.com"
firstName = "user"
lastName = "test"
department = "guess"
jobTitle = "poor iOS"
pictureUri = URL(string: "wrong")
headerUri = URL(string: "none")
bio = "China"
updatedDate = Date()
}
func listPropertiesWithValues(reflect: Mirror? = nil) -> [String: Any]{
let mirror = reflect ?? Mirror(reflecting: self)
if mirror.superclassMirror != nil {
self.listPropertiesWithValues(reflect: mirror.superclassMirror)
}
var yourDict = [String: Any]()
for (index, attr) in mirror.children.enumerated() {
if let property_name = attr.label {
//You can represent the results however you want here!!!
print("\(index): \(property_name) = \(attr.value)")
yourDict[property_name] = attr.value
}
}
return yourDict
}
}
Call like this:
let profile = RemoteProfileModel()
profile.listPropertiesWithValues()
In Swift Debugging and Reflection,
A mirror describes the parts that make up a particular instance

Adding query parameter to the GET url in iOS in Swift3

I have an URL with
https://api.asiancar.com/api/applicationsettings
It is basically a GET url so I need to pass a boolean "isMobile" and timestamp as query parameters . How to achieve this as the ultimate URL after passing the query will look like this:
https://api.asiancar.com/api/applicationsettings?timestamp=111122244556789879&isMobile=true
let queryItems = [
NSURLQueryItem(timestamp: "1234568878788998989", isMobile: true),
NSURLQueryItem(timestamp: "1234568878788998989", isMobile: true)
]
let urlComps = NSURLComponents(string: "www.api.asiancar.com/api/applicationsettings")!
urlComps.queryItems = queryItems
let URL = urlComps.URL!
Am I doing right or any other modification ? please tell.
Unless you have subclassed NSURLQueryItem, then your init method is not correct. Per Apple's documentation for NSURLQueryItem, the init method signature is:
init(name: String, value: String?)
This means your query items should be created like this:
let queryItems = [NSURLQueryItem(name: "timestamp" value: "1234568878788998989"), NSURLQueryItem(name: "isMobile", value: "true")]
This will properly add them to the url in the format you are expecting.
You can try an alternative way by using String
let baseUrlString = "https://api.asiancar.com/api/"
let timeStamp = 1234568878788998989
let isMobile = true
let settingsUrlString = "\(baseUrlString)applicationsettings?timestamp=\(timeStamp)&isMobile=\(isMobile)"
print(settingsUrlString)
let url = URL(string: settingsUrlString)
output : https://api.asiancar.com/api/applicationsettings?timestamp=1234568878788998989&isMobile=true
Try this :
let API_PREFIX = "www.api.asiancar.com/api/applicationsettings"
var url : URL? = URL.init(string: API_PREFIX + queryItems(dictionary: [name: "isMobile", value: "true"] as [String : Any]))
func queryItems(dictionary: [String:Any]) -> String {
var components = URLComponents()
print(components.url!)
components.queryItems = dictionary.map {
URLQueryItem(name: $0, value: $1 as String)
}
return (components.url?.absoluteString)!
}

How to decode the url about json data?

I got json data from server like this.
[
"http:\/\/helloWord.com\/user\/data\/000001.jpg?1497514193433",
"http:\/\/helloWord.com\/user\/data\/000002.jpg?1500626693722"
]
And What should I do to get each user url?
I try to use removingPercentEncoding, but it doesn't work.
What should I do?
Thanks.
let string:String = chatroom.avatar
let tempArr = string.components(separatedBy: ",")
var stringArr = Array<String>()
print("**tempArr\(tempArr)")
for a in tempArr {
var b = a.replacingOccurrences(of: "\"", with: "")
b = b.replacingOccurrences(of: "[", with: "")
b = b.replacingOccurrences(of: "]", with: "")
b = b.removingPercentEncoding //not working!!!!
print("b: \(b)")
//b: http:\/\/helloWord.com\/user\/data\/000001.jpg?1497514193433
//b: http:\/\/helloWord.com\/user\/data\/000002.jpg?1500626693722
}
I use swiftyJson
class User : Model {
var url:String = ""
func fromJson(_ json:JSON) {
url = json["url"].zipString
saveSqlite()
}
}
extension JSON {
var prettyString: String {
if let string = rawString() {
return string
}
return ""
}
var zipString: String {
if let string = rawString(.utf8, options: JSONSerialization.WritingOptions.init(rawValue: 0)) {
return string
}
return ""
}
}
Err, you shouldn't try to write your own JSON parser.
Try: https://github.com/SwiftyJSON/SwiftyJSON
It is one file of Swift code and makes using JSON much easier in Swift.
In swift 4 you will be able to use Structs to directly decode, but we're not there yet.
The apple way:
func read(payload: Data) throws -> [String]? {
guard let result = try JSONSerialization.jsonObject(with: payload, options: JSONSerialization.ReadingOptions.allowFragments) as? [String] else { return nil }
return result
}
Then for example you could read them out this way:
var userURLs: [URL] = []
for jsonURL in result {
guard let userURL = URL(string: jsonURL) else { continue }
userURLs.append(userURL)
}
This way you get only valid URL objects in your last result array.
If you get problems using the JSONSerialization code I described above it might be that it expects a different type. Then you'd have to use [Any] as a cast instead, or in case you have objects [String: Any] usually works. Keep in mind that in that case you will have to cast the objects you get from the array like so:
URL(string: (jsonURL as? String) ?? "")
Swifty JSON makes it easier to go about with the nullability, as it provides an easy way to safely traverse an object tree and return empty but non nil values!
It seems to me that you want to use removingPercentEncoding to remove escape characters - those backslashes? While removingPercentEncoding is to work on percent encoded characters, e.g. to convert http%3A%2F%2Fwww.url-encode-decode.com%2F to http://www.url-encode-decode.com/. So you are using it at the wrong place. Make sure to call this method only on the URLs that are percent encoded.
For this scenario, like others already suggested, use JSONSerialization is the way to go.

Swift encode & in the GET parameter

I have a simple GET request for login. Username is Silver and password is MOto&#10
I am using SwiftHttp framework for handling requests. On hitting login request, I always get response as false.
However on hitting the login request url on browser (replaced actual domain with server) I get true :
https://server/api/check-access/by-login-pass?_key=wlyOF7TM8Y3tn19KUdlq&login=silver&pass=MOto%26#10
There is something wrong with encoding & in the password. Though I have replaced it with percent encoding. Here is my code :
do {
let passwordString = self.convertSpecialCharacters(string: password.text!)
print("%#", passwordString)
let opt = try HTTP.GET(Constants.kLoginUrl, parameters: ["login": username.text!, "pass": passwordString])
opt.start { response in
if let err = response.error {
print("error: \(err.localizedDescription)")
return
}
print("opt finished: \(response.description)")
self.parseLoginResponse(response.data)
}
} catch _ as NSError {
}
And this is convertSpecialCharacters :
func convertSpecialCharacters(string: String) -> String {
var newString = string
let arrayEncode = ["&", "<", ">", "\"", "'", "-", "..."]
for (escaped_char) in arrayEncode {
newString = newString.encode(escaped_char)
}
return newString
}
Extension for encoding :
extension String {
func encode(_ chars: String) -> String
{
let forbidden = CharacterSet(charactersIn: chars)
return self.addingPercentEncoding(withAllowedCharacters: forbidden.inverted) ?? self
}
}
A suitable way is to use URLComponents which handles all percent encoding:
var urlComponents = URLComponents(string: "https://server/api/check-access/by-login-pass")!
let queryItems = [URLQueryItem(name:"_key", value:"wlyOF7TM8Y3tn19KUdlq"),
URLQueryItem(name:"login", value:"silver"),
URLQueryItem(name:"pass", value:"MOto&#10")]
urlComponents.queryItems = queryItems
let url = urlComponents.url
print(url) // "https://server/api/check-access/by-login-pass?_key=wlyOF7TM8Y3tn19KUdlq&login=silver&pass=MOto%26#10"
PS: I totally agree with luk2302's comment.
I've decided to go full custom for my GET-request, since everything else didn't want to work and got me angry. I used the request for something different though, like getting a list from our server. The login is done via POST requests which was easier.
However, to stick with GET-requests:
I needed characters like "+" and "/" encoded...
First I couldn't get the "+" encoded with the "stringByAddingPercentEncodingWithAllowedCharacters" method.
So I have built my own extension for String:
extension String
{
return CFURLCreateStringByAddingPercentEscapes(
nil,
self as CFString,
nil,
"!*'();:#&=+$,/?%#[]" as CFString,
CFStringBuiltInEncodings.UTF8.rawValue
) as String
}
2nd step was to add this to my url for the final request. I wanted to use URLQueryItems and add them to the url by using url.query or url.queryItems. Bad surprise: My already correctly encoded string got encoded again and every "%" inside of it became "%25" making it invalid. -.-
So now I have appended each encoded value to a string which will be added to the url. Doesn't feel very "swift" but ok..
let someUrl = "https://example.com/bla/bla.json"
var queryString = ""
var index = 0
// dicParam is of type [String: AnyObject] with all needed keys and values for the query
for (key, value) in dicParam
{
let encodedValue = (value as! String).encodeUrl()
if index != 0
{
queryString.append("&\(key)=\(encodedValue)")
}
else
{
queryString.append("?\(key)=\(encodedValue)")
}
index += 1
}
let url = URLComponents(string: someUrl + queryString)!
Hope this helps someone and saves a few hours :/

Resources