I am trying to unwrap the raw value of an enum type in func toDictionary() , but I get an error.
How can I fix this?
enum ChatFeatureType: String {
case tenants
case leaseholders
case residents
}
class Chat {
var featureType: ChatFeatureType?
init(featureType: ChatFeatureType? = nil
self.featureType = featureType
}
//download data from firebase
init(dictionary : [String : Any]) {
featureType = ChatFeatureType(rawValue: dictionary["featureType"] as! String)!
}
func toDictionary() -> [String : Any] {
var someDict = [String : Any]()
// I get error on the line below: Value of optional type 'ChatFeatureType?' not unwrapped; did you mean to use '!' or '?'?
someDict["featureType"] = featureType.rawValue ?? ""
}
}
As featureType is an optional you have to add ? or ! as the error says
someDict["featureType"] = featureType?.rawValue ?? ""
But be aware that your code reliably crashes when you create an instance of Chat from a dictionary and the key does not exist because there is no case "".
Actually the purpose of an enum is that the value is always one of the cases. If you need an unspecified case add none or unknown or similar.
This is a safe version
enum ChatFeatureType: String {
case none, tenants, leaseholders, residents
}
class Chat {
var featureType: ChatFeatureType
init(featureType: ChatFeatureType = .none)
self.featureType = featureType
}
//download data from firebase
init(dictionary : [String : Any]) {
featureType = ChatFeatureType(rawValue: dictionary["featureType"] as? String) ?? .none
}
func toDictionary() -> [String : Any] {
var someDict = [String : Any]()
someDict["featureType"] = featureType.rawValue
return someDict
}
}
I'm grabbing metadata from an MPMediaItem like this:
let url = item.value(forProperty:MPMediaItemPropertyAssetURL) as? NSURL
let asset = AVURLAsset(url: url! as URL, options: nil)
let metaArray = asset.metadata
for metadata in metaArray{
print("-----metadata:\(metadata)")
print("-----metadata.key:\(String(describing: metadata.key))")
}
However, when I get a block of metadata printed the "key" is printed as a numeric value instead of "pcst" as shown in the printout:
-----metadata:<AVMetadataItem: 0x1740153f0, identifier=itsk/pcst, keySpace=itsk, key class = __NSCFNumber, key=pcst, commonKey=(null), extendedLanguageTag=(null), dataType=com.apple.metadata.datatype.int8, time={INVALID}, duration={INVALID}, startDate=(null), extras={
dataLength = 1;
dataType = 21;
dataTypeNamespace = "com.apple.itunes";
}, value=1>
-----metadata.key:Optional(1885565812)
This is happening for all of the metadata/keys (there are 29 in this particular media item).
Also note that this line of code:
let realString = NSString(string: metadata.key! as! String)
causes this error:
Could not cast value of type '__NSCFNumber' (0x1b80dcdf0) to 'NSString' (0x1b80edae8).
How can I get the string value for the key ("pcst") ?
May be what you are looking for is identifier property of AVMetadataItem.
for metadata in metaArray{
print(metadata.identifier ?? "DefaultValue")
}
In case others want to see the code I'm using:
func returnKeyString(_ inVal: String)->String{
// expecting the metadata for "identifier" as input - returns key value
// eg "itsk/ldes" -> "ldes"
// or "id3/%00WFD" etc. -> "wfd"
var sFinal:String = ""
if (inVal.contains("/")){
sFinal = (inVal.components(separatedBy: "/")[1])
}
if sFinal.contains("%"){
sFinal = sFinal.components(separatedBy: "%")[1]
let index1 = sFinal.index(sFinal.startIndex, offsetBy: 2)
sFinal = sFinal.substring(from: index1)
}
return sFinal.lowercased()
}
I got Encrypted data from API hit by below method
URLSession.shared.dataTask(with: url!)
converted data into JSON but still it is encrypted
var json = try(JSONSerialization.jsonObject(with: data!, options: .allowFragments))
converted it into string
let arr:String = json as! String
decrypted it
let jsonText = arr.fromBase64()//extension method, given end of question
now it is in Json Formate as below (this is only 1 record, there are more than 1 records in Json string)
{
"CompanyAlt_Key": 1,
"Company_Name": "XYZ LTD",
"TableName": "CompanyList"
},
I have a model of same type
public class CompanyList {
public var companyAlt_Key : Int?
public var company_Name : String?
public var tableName : String?
}
here is fromBase64 method
func fromBase64() -> String {
let data = NSData.init(base64Encoded: self, options: []) ?? NSData()
return String(data: data as Data, encoding: String.Encoding.utf8) ?? ""
}
I am facing problem to get the Json String into an array of type CompanyList class
Help would be appreciate
You'll need to convert your jsonString to data first:
let jsonData = jsonString.data(using: .utf8)!
The convert the data to an array
let array = JSONSerialization.jsonObject(with: jsonData, options: nil) as? [[String: Any]]
Then iterate through the array…
let companies = array?.map {
return CompanyList(dictionary: $0)
}
Implement an init method for your CompanyList, passing in a dictionary for each record in your response…
public class CompanyList {
public var companyAlt_Key : Int?
public var company_Name : String?
public var tableName : String?
init(dictionary: [String: Any]) {
companyAlt_Key = dictionary["companyAlt_Key"] as? Int
company_Name = dictionary["company_Name"] as? String
tableName = dictionary["tableName"] as? String
}
}
You can also use this to validate the data. If the fields in your class are non-optional, you can use an optional init as follows…
public class CompanyList {
public var companyAlt_Key : Int
public var company_Name : String
public var tableName : String
init?(dictionary: [String: Any]) {
guard let companyAlt_Key = dictionary["companyAlt_Key"] as? Int,
let company_Name = dictionary["company_Name"] as? String,
let tableName = dictionary["tableName"] as? String else {
return nil
}
self.companyAlt_Key = companyAlt_Key
self.company_Name = company_Name
self.tableName = tableName
}
}
If you're using an optional init, use flatMap to ensure you don't have any optional elements in your array…
let companies = array?.flatMap {
return CompanyList(dictionary: $0)
}
I am updating my code to swift3.0 but getting ambiguous refrence to member? What wrong i might be doing. Here is the method I am getting error in.
open class func parseJsonTenantList(_ list: [NSDictionary]?, strElementName: String, attrName1: String, attrNameValue2: String) -> [TenantRegister]
{
var renantList: [TenantRegister] = []
var key: String?
if let dict : [NSDictionary] = list {
var value: String?
for i in 0..<dict.count {
/// if attribute name doesn't match then it returns nil
if let s1: AnyObject = dict[i].value(forKey: attrName1)
{
key = s1 as? String
}
if let s2: AnyObject = dict[i].value(forKey: attrNameValue2)
{
value = s2 as? String
}
if (!(String.stringIsNilOrEmpty(value) && String.stringIsNilOrEmpty(key)))
{
let t: TenantRegister = TenantRegister()
t.name = key
t.tenantId = Guid(value!)
renantList.append(t)
}
}
}
return renantList
}
The issue is you are using NSDictionary, to solved your problem simply cast the list to Swift's native type [[String:Any]] and then use subscript with it instead of value(forKey:)
if let dict = list as? [[String:Any]] {
var value: String?
for i in 0..<dict.count {
/// if attribute name doesn't match then it returns nil
if let s1 = dict[i][attrName1] as? String
{
key = s1
}
if let s2 = dict[i][attrNameValue2] as? String
{
value = s2
}
if (!(String.stringIsNilOrEmpty(value) && String.stringIsNilOrEmpty(key)))
{
let t: TenantRegister = TenantRegister()
t.name = key
t.tenantId = Guid(value!)
renantList.append(t)
}
}
}
In Swift use native type Dictionary [:] and Array [] instead of NSDictionary and NSArray to overcome this type of issues.
Basically I have a Youtube URL as string, I want to extract the video Id from that URL. I found some code in objective c that is as below:
NSError *error = NULL;
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:#"?.*v=([^&]+)"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:youtubeURL
options:0
range:NSMakeRange(0, [youtubeURL length])];
if (match) {
NSRange videoIDRange = [match rangeAtIndex:1];
NSString *substringForFirstMatch = [youtubeURL substringWithRange:videoIDRange];
}
When I am converting this code to swift3 that is:
var error: Error? = nil
var regex = try! NSRegularExpression(pattern: "?.*v=([^&]+)", options: .caseInsensitive)
var match = regex!.firstMatch(in: youtubeURL, options: [], range: NSRange(location: 0, length: youtubeURL.length))!
if match {
var videoIDRange = match.rangeAt(1)
var substringForFirstMatch = (youtubeURL as NSString).substring(with: videoIDRange)
}
Gives error as:
fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=2048 "The value “?.*v=([^&]+)” is invalid."
Can anybody help me about this error or anybody explain how to get video id from url in Swift 3.
Thanks in advance
Safer version (without force unwrapping !):
extension String {
var youtubeID: String? {
let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let range = NSRange(location: 0, length: count)
guard let result = regex?.firstMatch(in: self, range: range) else {
return nil
}
return (self as NSString).substring(with: result.range)
}
}
Examples:
"https://www.youtube.com/watch?v=C0DPdy98e4c".youtubeID // "C0DPdy98e4c"
"https://youtube.com/watch?v=C0DPdy98e4c".youtubeID // "C0DPdy98e4c"
"www.youtube.com/watch?v=C0DPdy98e4c".youtubeID // "C0DPdy98e4c"
"youtube.com/watch?v=C0DPdy98e4c".youtubeID // "C0DPdy98e4c"
"https://youtu.be/C0DPdy98e4c".youtubeID // "C0DPdy98e4c"
"youtu.be/C0DPdy98e4c".youtubeID // "C0DPdy98e4c"
Credits: Usman Nisar's answer
I have a different way of doing this using URLComponents. You then just select the 'v' parameter from the url, if it exists.
func getYoutubeId(youtubeUrl: String) -> String? {
return URLComponents(string: youtubeUrl)?.queryItems?.first(where: { $0.name == "v" })?.value
}
And then pass in a Youtube url like this:
print (getYoutubeId(youtubeUrl: "https://www.youtube.com/watch?v=Y7ojcTR78qE&spfreload=9"))
Swift 5
var youtubeURLs = [
"http://www.youtube.com/watch?v=-wtIMTCHWuI",
"http://www.youtube.com/v/-wtIMTCHWuI?version=3&autohide=1",
"http://youtu.be/-wtIMTCHWuI",
"http://www.youtube.com/oembed?url=http%3A//www.youtube.com/watch?v%3D-wtIMTCHWuI&format=json",
"https://youtu.be/uJ2PZaO1N5E",
"https://www.youtube.com/embed/M7lc1UVf-VE",
"http://www.youtube.com/attribution_link?a=JdfC0C9V6ZI&u=%2Fwatch%3Fv%3DEhxJLojIE_o%26feature%3Dshare",
"https://www.youtube.com/attribution_link?a=8g8kPrPIi-ecwIsS&u=/watch%3Fv%3DyZv2daTWRZU%26feature%3Dem-uploademail"
]
func getVideoID(from urlString: String) -> String? {
guard let url = urlString.removingPercentEncoding else { return nil }
do {
let regex = try NSRegularExpression.init(pattern: "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)", options: .caseInsensitive)
let range = NSRange(location: 0, length: url.count)
if let matchRange = regex.firstMatch(in: url, options: .reportCompletion, range: range)?.range {
let matchLength = (matchRange.lowerBound + matchRange.length) - 1
if range.contains(matchRange.lowerBound) &&
range.contains(matchLength) {
let start = url.index(url.startIndex, offsetBy: matchRange.lowerBound)
let end = url.index(url.startIndex, offsetBy: matchLength)
return String(url[start...end])
}
}
} catch {
print(error.localizedDescription)
}
return nil
}
for url in youtubeURLs {
print("Video id: \(getVideoID(from: url) ?? "NA") for url: \(url)")
}
Result:
Video id: -wtIMTCHWuI for url: http://www.youtube.com/watch?v=-wtIMTCHWuI
Video id: -wtIMTCHWuI for url: http://www.youtube.com/v/-wtIMTCHWuI?version=3&autohide=1
Video id: -wtIMTCHWuI for url: http://youtu.be/-wtIMTCHWuI
Video id: -wtIMTCHWuI for url: http://www.youtube.com/oembed?url=http%3A//www.youtube.com/watch?v%3D-wtIMTCHWuI&format=json
Video id: uJ2PZaO1N5E for url: https://youtu.be/uJ2PZaO1N5E
Video id: M7lc1UVf-VE for url: https://www.youtube.com/embed/M7lc1UVf-VE
Video id: EhxJLojIE_o for url: http://www.youtube.com/attribution_link?a=JdfC0C9V6ZI&u=%2Fwatch%3Fv%3DEhxJLojIE_o%26feature%3Dshare
Video id: yZv2daTWRZU for url: https://www.youtube.com/attribution_link?a=8g8kPrPIi-ecwIsS&u=/watch%3Fv%3DyZv2daTWRZU%26feature%3Dem-uploademail
Here is code to extract youtube video id from any youtube url:
(Swift)
func extractYoutubeId(fromLink link: String) -> String {
let regexString: String = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
let regExp = try? NSRegularExpression(pattern: regexString, options: .caseInsensitive)
let array: [Any] = (regExp?.matches(in: link, options: [], range: NSRange(location: 0, length: (link.characters.count ))))!
if array.count > 0 {
let result: NSTextCheckingResult? = array.first as? NSTextCheckingResult
return (link as NSString).substring(with: (result?.range)!)
}
return ""
}
A Swift 4 version using the elegant flatMap:
func extractYouTubeId(from url: String) -> String? {
let typePattern = "(?:(?:\\.be\\/|embed\\/|v\\/|\\?v=|\\&v=|\\/videos\\/)|(?:[\\w+]+#\\w\\/\\w(?:\\/[\\w]+)?\\/\\w\\/))([\\w-_]+)"
let regex = try? NSRegularExpression(pattern: typePattern, options: .caseInsensitive)
return regex
.flatMap { $0.firstMatch(in: url, range: NSMakeRange(0, url.count)) }
.flatMap { Range($0.range(at: 1), in: url) }
.map { String(url[$0]) }
}
This method uses a regex that detects most of the possible YouTube URL formats (.be/*, /embed/, /v/ - you can find the full list here).
Your first problem is you are not escaping ? in your expression. ? is reserved character and if you want to use it in your expressions, you must escape with \ and since \ is used also to escape " character you must escape ? with double backslash something like \\?. So according to above information, following code correctly extracts the videoId
let youtubeURL = "https://www.youtube.com/watch?v=uH8o-JTHJdM"
let regex = try! NSRegularExpression(pattern: "\\?.*v=([^&]+)", options: .caseInsensitive)
let match = regex.firstMatch(in: youtubeURL, options: [], range: NSRange(location: 0, length: youtubeURL.characters.count))
if let videoIDRange = match?.rangeAt(1) {
let substringForFirstMatch = (youtubeURL as NSString).substring(with: videoIDRange)
} else {
//NO video URL
}
Some samples of Youtube's url:
let urls: [String] = [
"www.youtube-nocookie.com/embed/up_lNV-yoK4?rel=0",
"http://www.youtube.com/watch?v=peFZbP64dsU",
"http://www.youtube.com/watch?v=cKZDdG9FTKY&feature=channel",
"http://youtube.com/v/dQw4w9WgXcQ?feature=youtube_gdata_player",
"http://youtube.com/?v=dQw4w9WgXcQ&feature=youtube_gdata_player",
"http://youtu.be/6dwqZw0j_jY",
"http://youtu.be/dQw4w9WgXcQ?feature=youtube_gdata_playe",
"http://youtube.com/vi/dQw4w9WgXcQ?feature=youtube_gdata_player",
"http://youtube.com/?vi=dQw4w9WgXcQ&feature=youtube_gdata_player",
"http://youtube.com/watch?vi=dQw4w9WgXcQ&feature=youtube_gdata_player",
"http://www.youtube.com/user/Scobleizer#p/u/1/1p3vcRhsYGo?rel=0",
"http://www.youtube.com/user/SilkRoadTheatre#p/a/u/2/6dwqZw0j_jY",
"1p3vcRhsY02"
]
My extension based on Islam Q. solution:
private extension String {
var youtubeID: String? {
let pattern = "((?<=(v|V|vi)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=vi=)|(?<=/u/[0-9_]/)|(?<=embed/))([\\w-]++)"
let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let range = NSRange(location: 0, length: count)
guard let result = regex?.firstMatch(in: self, range: range) else {
return count == 11 ? self : nil
}
let id = (self as NSString).substring(with: result.range)
return id.count == 11 ? id : nil
}
}
Recently youtube added a prefix to live videos.
I used this solution from the thread
https://stackoverflow.com/a/62651531/16457129
And I just added (?<=live/)
let regex = try NSRegularExpression.init(pattern: "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/)|(?<=live/))([\\w-]++)", options: .caseInsensitive)
To get video Id from Youtube Url, use code # Swift4 :
var videoId = ""
if youtubeLink.lowercased().contains("youtu.be"){
linkString = youtubeLink
if let range = linkString.range(of: "be/"){
videoId = youtubeLink[range.upperBound...].trimmingCharacters(in: .whitespaces)
}
}
else if youtubeLink.lowercased().contains("youtube.com"){
linkString = youtubeLink
if let range = linkString.range(of: "?v="){
videoId = youtubeLink[range.upperBound...].trimmingCharacters(in: .whitespaces)
}
}
Hope will be helping! :)