Converting Base64 to data returning nil - ios

I am trying to convert base64 string to image, I checked the json response, base64 string is not empty, but Data returns nil in between.
let base64String = image.Image_bytes_1
var data = Data(base64Encoded: base64String!, options: .ignoreUnknownCharacters)
let image = UIImage(data: data! as Data)
imageView.image = image
at line#4 getting this below error
Thread 3: Fatal error: Unexpectedly found nil while unwrapping an
Optional value

The Data initializer you are using, init(base64Encoded:options:) is declared as init?(base64Encoded base64Data: Data, options: Data.Base64DecodingOptions = [])
That's known as a "failable initializer", which means it can return nil. (note the question mark after init in the declaration.)
If the base64 data is not well-formed, it may fail and return nil.
Stop using force-unwrapping. Rewrite using optional binding:
if let base64String = image.Image_bytes_1,
let data = Data(base64Encoded: base64String, options: .ignoreUnknownCharacters),
let image = UIImage(data: data) {
imageView.image = image
} else {
print("Unable to load base64 data and convert to image")
}
Edit:
As workingdog pointed out in their comment, your code does not make sense:
let base64String = image.Image_bytes_1 // line 1
var data = Data(base64Encoded: base64String!, options: .ignoreUnknownCharacters) // line 2
let image = UIImage(data: data! as Data) // line 3
imageView.image = image // line 4
Line 1 references something called image. You don't show the code that declares it, so we don't know what it is.
Then in line 3, you declare a new local constant also named image. If the original image is an instance variable of your class, and the code you posted is inside a function, you are creating a new local variable that overrides the other variable called image. I strongly advise against using the same variable name in different levels of scope. That is confusing at best, and causes errors at worst.

Related

How to convert svg+xml base64 to UIImage?

I simply have string like this:
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjYwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxwYXRoIGlkPSJzdmdfMSIgc3Ryb2tlPSIjMDAwIiBmaWxsPSIjZmZmIi8+CiAgPHJlY3Qgcng9IjYyIiBzdHJva2Utd2lkdGg9IjEwIiBpZD0ic3ZnXzIiIGhlaWdodD0iMzAzIiB3aWR0aD0iNjI5IiB5PSIxMTIiIHg9IjkxIiBzdHJva2U9IiMwMDAiIGZpbGw9IiNmZmYiLz4KICA8ZGVmcz4KICA8cmVjdCByeT0iNjMiIHJ4PSI2MyIgc3Ryb2tlLXdpZHRoPSIxMCIgaWQ9InJlY3QiIGhlaWdodD0iMTI2IiB3aWR0aD0iMTI2IiB5PSIxNTAiIHg9IjE0MCIgc3Ryb2tlPSIjMDAwIiBmaWxsPSIjZmZmIi8+CiAgPGNsaXBQYXRoIGlkPSJjbGlwIj4KICAgICAgPHVzZSB4bGluazpocmVmPSIjcmVjdCIvPgogICAgPC9jbGlwUGF0aD4KPC9kZWZzPgoKICA8dXNlIHhsaW5rOmhyZWY9IiNyZWN0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZT0iYmxhY2siLz4KICA8aW1hZ2UgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFHUUFBQUJrQ0FJQUFBRC9nQUlEQUFBRENrbEVRVlI0bk95ZFhVaFRjUnlHZC9SUUpFSE1WU3BwdFJiWWwwWWZHcWxZTVNnS2pNZ1V2SWt5R3RLY2RKZkVvckpGUVlyV3hReGNRUVcxQzhHaE80WE1ncUNJRWxtME1ZTkZ3VENFR3BSRk9jaWllOEVYM3Z2M3VYM1lPRHo4THM2Qi8va2QwNUdldFMxTUpERUI3RlQ0TTdDMWxoMVlZNkFOMkZ1aExMQ1B5bnFBUFhiMU1MQ2w2OUJ2dTE5ZkF6WVBPREVQeFNKUUxBTEZJbEFzQXNVaVVDd0N4U0pRTEFKejZWY1Q2TWtYZm1BYk8xY0JHNjFZQVd5aXJSN1l2dXFMd0s3SlRRRTduZDRQN0pleE9MQ0ZSY2VCMVdRUktCYUJZaEVvRm9GaUVTZ1dnV0lSS0JhQlloR1lXNWNiUUR2dHU0RDFqZXdEZHMvWlA4Q1d1SXVBdlRsVEJ1eUE3eVN3VnFRZjJPR0NsY0F1c3lXQTFXUVJLQmFCWWhFb0ZvRmlFU2dXZ1dJUktCYUJZaEdZUXpjK0FqMmJPd2RzUjBzcHNET2JEZ0o3enhVR2RuaXpHOWdsK2FlQWRlU2paNUx5WURHd3llYTd3R3F5Q0JTTFFMRUlGSXRBc1FnVWkwQ3hDQlNMUUxFSXpPTFlKNkNUbFU1Z2ExNjlBL2IzNmc1Z2I5dlBBMXUrRzkyRkY0NC9BN1lsTUFoc3dJbm1JNXhCWjJ3MFdRU0tSYUJZQklwRm9GZ0Vpa1dnV0FTS1JhQllCRVpYNmkzUU93TG9qdlpJNndmMDMyUG90UHJjNDFGZzMzaEhnTTAyUGdIMlVud2pzTDJIMERWWDJaSFZaQkVvRm9GaUVTZ1dnV0lSS0JhQlloRW9Gb0ZpRVJqcEp2VGVaMmNFdlcvNnZtRVJzTk1KZEtiOHg0TmVZUE1HMFlhY254UGJnYTNMZEFQYjAzNEMyQzAxZTlGVkFTZm1vVmdFaWtXZ1dBU0tSYUJZQklwRm9GZ0Vpa1ZndEhxalFLZlFvaHJiL2ZwSllFYzlCNEIxUjBQQTlnODFBN3Y0NzNWZy9hZVBBcnZUampaZ1B1eERwNFkwV1FTS1JhQllCSXBGb0ZnRWlrV2dXQVNLUmFCWUJFWW02UVg2elBNVXNITU5QbURqbmlwZ3ZlMXJnYlVLU29EMVAwVjdLaS9IcW9FTlhrRDdNYk5KQzFoTkZvRmlFU2dXZ1dJUktCYUJZaEVvRm9GaUVTZ1dnZWtJTlFFZGZPa0M5b3BaQit6M0N2UjFwRzIxNkp0TnY2dzd3RlorV3cvc1A5ODRzQnM4WGNER1hEbGdOVmtFaWtXZ1dBU0tSYUJZQklwRm9GZ0Vpa1dnV0FUL0F3QUEvLy9yWFpLVzhmMG5SQUFBQUFCSlJVNUVya0pnZ2c9PSIgd2lkdGg9IjEwMCIgaGVpZ2h0PSIxMDAiIHk9IjE2MCIgeD0iMTYwIiBjbGlwLXBhdGg9InVybCgjY2xpcCkiLz4KCiAgPHRleHQgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgdGV4dC1hbmNob3I9InN0YXJ0IiBmb250LWZhbWlseT0iTm90byBTYW5zIEpQIiBmb250LXNpemU9IjI0IiBpZD0ic3ZnXzQiIHk9IjM0MiIgeD0iMTc5IiBzdHJva2Utd2lkdGg9IjAiIHN0cm9rZT0iIzAwMCIgZmlsbD0iIzAwMDAwMCI+YXNnZGhqYWdhc2Rqa2FzZGg8L3RleHQ+CiAgPHRleHQgdHJhbnNmb3JtPSJtYXRyaXgoMTguMDU3LCAwLCAwLCA3LjM3MzIsIC04NDI5LjI0LCAtMTkxNS40NSkiIHhtbDpzcGFjZT0icHJlc2VydmUiIHRleHQtYW5jaG9yPSJzdGFydCIgZm9udC1mYW1pbHk9IidEYW5jaW5nIFNjcmlwdCciIGZvbnQtc2l6ZT0iMSIgaWQ9InN2Z183IiB5PSIyOTAuNTEwNjEiIHg9IjQ5Ny4wODEyNyIgc3Ryb2tlLXdpZHRoPSI4IiBzdHJva2U9IiMwMDAiIGZpbGw9IiNmZmYiPmU8L3RleHQ+CiA8L2c+Cjwvc3ZnPg=="
How do I convert it into UIImage using SVGKit cocoapod library?
For now I simply use:
var image: UIImage? {
guard let imageEncodedString = imageEncodedString else {
return nil
}
return SVGKImage(data: Data(base64Encoded: imageEncodedString))?.uiImage //crash here inside init
}
The beginning of the string is not base64, that's why it's failing. You need to remove first data:image/svg+xml;base64,.
You have a Data URI.
It should be like that:
data:[<media type>][;base64],<data>
You currently have:
data:image/svg+xml;base64,theBase64Image
Now, you can either remove always data:image/svg+xml;base64, from your string:
let dataURI = "data:image/svg+xml;base64,theBase64Image"
let base64String = dataURI.replacingOccurrences(of: "data:image/svg+xml;base64,", with: "")
You can also check before hand if hasPrefix() to ensure that it has the expected dataURI. You could also use a Regex, NSScanner, etc. to do so.
But since you expect SVG in base64, hasPrefix() and replacingOccurrences(of:with:) should be enough.

How to encode and decode a nested array using Codable and PropertyListEncoder?

I have a UICollectionView with multiple sections. Thus my data source for the collection view is a nested array of type [[DayData?]]. There is an instance of DayData for every cell and each inside array corresponds with each section. In DayData.swift, DayData has one property, a String and conforms to Codable. The problem I am struggling with is how to properly encode and decode this nested array.
static func saveToFile(days: [[DayData?]]) {
let propertyListEncoder = PropertyListEncoder()
let encodedDays = try? propertyListEncoder.encode(days)
try? encodedDays?.write(to: archiveURL,
options: .noFileProtection)
}
static func loadFromFile() -> [[DayData?]]? {
let propertyListDecoder = PropertyListDecoder()
if let retrievedDayData = try? Data(contentsOf: archiveURL),
let decodedDays = try?
propertyListDecoder.decode(Array<Array<DayData>>.self, from:
retrievedDayData) {
return decodedDays
}
return nil
}
Right now I call saveToFile(days:) after the String property of an element DayData in the nested array is reassigned like this:
dayDataArray[indexPath!.section][indexPath!.item]?.moodColor =
When I call loadFromFile(), it returns nil, so my data isn't saving. The program builds successfully.
I would really appreciate any help. I'm new to iOS and Swift, so I apologize if this is a dumb question.
EDIT: The loadFromFile() method is throwing this error: "Expected to decode Dictionary<String, Any> but found a string/data instead." I'm guessing this means that the data is decoding into a String rather than a nested array of DayData objects, but I'm not sure why it's doing this or how to fix it.
EDIT: I made DayData not optional, and it works now.

get a string from UIImage in swift

I have image loaded from UIImagePickerController into UIImageView
I need to convert the image into string to send it to the server
This is my code but it gives an error
var imageData:String = "";
if let unwrappedImage = profileImage.image {
let imageNSData : NSData = UIImageJPEGRepresentation(unwrappedImage, 1.0)!;
imageData = (NSString(data:imageNSData, encoding:NSUTF8StringEncoding) as String?)!
}
I am getting the following exception
fatal error: unexpectedly found nil while unwrapping an Optional value
can any one help please
Convert the data information of a image to a string , you will get a very very very long string, why not loaded the data to the server. Alamofire can do it easily, just see the uploading file part.

Swift optionals and their instantiation

I'm new to Swift. I'll explain what I'm trying to do in Java terms and hopefully someone can help me understand.
I want a class scoped array that is instantiated/set in viewDidLoad of a view controller. It sounds simple enough, but this is what I had to do to get it to work. Could someone explain to me why the _dictionary must be instantiated as an empty array and why I need to use as? when unpacking dictionary even though the componentsSeparatedByString function returns an array? Thanks.
class ViewController: UIViewController, UITextFieldDelegate
{
var _dictionary : [String] = []
override func viewDidLoad()
{
super.viewDidLoad()
let bundle = NSBundle.mainBundle()
let path = bundle.pathForResource(“TextFile”, ofType: "txt")
var err: NSError?
let dico = NSString(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: &err)
if let dictionary = dico?.componentsSeparatedByString("\n") as? [String]
{
_dictionary = dictionary
}
else
{
println("Error reading dictionary")
}
}
}
_dictionary must be given an initial value because all instance properties must be given an initial value. That is a Swift safety feature to make sure that all instances are well-formed at birth. You could have done this by initializing _dictionary in an actual initializer, but you didn't. You chose to give it its first "real" value in viewDidLoad which is much later. Therefore you have forced yourself to supply a "fake" initial value until such time as viewDidLoad comes along and gives you a "real" initial value.
I don't understand your other question because I don't know what "unpacking dictionary" means. But perhaps you are referring to the rest of the stuff in this code. I'll talk you through it.
dico is an Optional wrapping a String. It is an Optional because the contentsOfFile: initializer of String returns an Optional - it is a failable initializer. That is because there might be no such file, or that file might not have that encoding, in which case the initializer needs to return nil.
So now dico is an Optional wrapping a String that must be unwrapped - or nil. So you do unwrap it as dico? in the next line. dico? is a String at that point, assuming that dico was not nil.
Then you call componentsSeparatedByString. It returns an array of AnyObject. So you have chosen to cast it down to an array of String using as?. I don't know why you chose to use as? since you know it will be an array of String if we get to this point - personally, I would have used as. But in any case, as? always returns an Optional! So you unwrap that, optionally, by using an if let conditional binding.
The irony throughout is that _dictionary is not and never was or will be a dictionary - it is an array. Your name for this (and for dictionary) is very poorly chosen! dico is a String, and dictionary and _dictionary are arrays. There is not a dictionary in sight.
Assuming we keep your rather odd names, though, you could have done all this much more briefly and clearly, like this:
var err : NSError?
if let dico = NSString(contentsOfFile: path!,
encoding: NSUTF8StringEncoding, error: nil) {
_dictionary = dico.componentsSeparatedByString("\n") as [String]
} else {
println(err)
}
Moreover, if you start with the String class instead of the NSString class, then componentsSeparatedByString will be an array of String instead of an untyped NSArray (i.e. an array of AnyObject), and you can skip the cast:
var err : NSError?
if let dico = String(contentsOfFile: path!,
encoding: NSUTF8StringEncoding, error: nil) {
_dictionary = dico.componentsSeparatedByString("\n")
} else {
println(err)
}

Encoding/decoding arbitrary binary data to string in swift/objective-c

I need to encode/decode an arbitrary NSData object into a String/NSString. Here's what I have for encoding:
var avatar64 = self.avatar.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromRaw(0)!);
let avatarData = NSData(base64EncodedString: avatar64, options: NSDataBase64DecodingOptions.fromRaw(0)!);
let avatar = NSString(data: avatarData, encoding: NSUTF8StringEncoding);
But avatar is nil. What am I doing wrong?
Your first step already creates a Base64-encoded string of the data in self.avatar:
var avatar64 = self.avatar.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromRaw(0)!);
Your second step decodes the Base64 string again, so that avatarData contains the same
binary data as your original self.avatar:
let avatarData = NSData(base64EncodedString: avatar64, options: NSDataBase64DecodingOptions.fromRaw(0)!);
Finally, your third step tries to create a string from the original (binary) data:
let avatar = NSString(data: avatarData, encoding: NSUTF8StringEncoding);
This fails because the data is not a valid UTF-8 sequence.
In short: Just remove the third and second line.

Resources