I have extracted OSX English language dictionary and want to use it in my Swift iPhone app. It has about 236,000 words which I have added to a swift string array.
When I try to run the build, it takes a long time to compile and then throws Segmentation Fault 11
Is this because the array is too big?
Am I going the correct path trying to add english dictionary in my project?
You should probably not store this as a single string. There are more efficient data structures that you can use, such as a trie. You should also consider not loading the entire content into memory at one point but be able to navigate it from the filesystem.
I was able to solve this problem by adding the actual dictionary text file into my xcode project. then utilize below code to fill words from the file to an array. it was pretty fast.
let path = NSBundle.mainBundle().pathForResource("dict2", ofType: "txt")
let dico = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)
let dict = dico!.componentsSeparatedByString("\n")
Hope it helps someone.
Related
I'm writing an iOS Swift app to fetch metadata from DJI drone images. I'm trying to access the Xmp.drone-dji.X metadata. The iOS/Swift CGImageSource and CGImageMetadata libraries/classes get almost all of the metadata out of the image but not the Xmp.drone-dji. When I get a list of tags, those tag/values are not listed. I know the tags/data are in the images because I've examined the images using exif, exiv2, etc.
Any suggestions?
Here is the code I'm using so far:
result.itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier)
{ data, err in
if let data = data {
let src = CGImageSourceCreateWithData(data as CFData,nil)!
let md = CGImageSourceCopyPropertiesAtIndex(src,0,nil) as! NSDictionary
let md2 = CGImageSourceCopyMetadataAtIndex(src,0,nil)
}
Thanks,
Bobby
So, after a lot of searching, trial and error, I have found an answer.
I was not able to get any of the CGImage swift libraries to extract this info for me.
Adobe has a c++ library that parses xmp/xml data out of images and it purports to support iOS. I didnt want the hassle of building c++ on iOS, importing that into Xcode and then dealing with the fact that thrown errors do not propagate well from c++/objectiveC to Swift.
So, at a high level, I did the following:
get the bytes of the raw image as CFData or Data then cast to a String
then use String.range() to find beginning of XML/XMP data in image
searching for substring <?xpacket begin
use String.range() to find end of XML/XMP data in image
using substring <?xpacket end.*?>
Extract the XML document out of image data String
Use Swift XMLParser class to parse the XML and then copying attributes and
elements as necessary. I just simply added what I wanted to already
existing Exif NSdictionary returned by CGImage classes.
Happy to answer questions on this approach. My code will eventually be uploaded to GitHub under OpenAthenaIOS project.
Bobby
I got little problem, I am downloading PDF and saving to location, I am using write method to save to location and everything seems to work on version iOS 10 and below, but I got problem with iOS11, I am getting false from method below, I checked path, and bytes and it is same on both devices.
(try? data.write(to: invoiceFileUrl, options: [.atomic])) != nil
try this
let data = NSData(contentsOf:url! as URL)
data?.write(to:invoiceFileUrl, atomically: true)
Have you tried simply moving the file around? I am guessing you are using URLSession to download said file ( or you should anyway ).
Then you can use FileManager to move the temporary file to your documents or whatever desired directory in your app's container.
FileManager.default.moveItem(at:temporaryURL, to: destinationURL)
In case you prefer using paths there is also:
FileManager.default.moveItem(atPath: temporaryPath, toPath: destinationPath)
Though I personally don't use paths often (anymore) because it can lead to a whole load of inconsistencies and other issues you just don't want to deal with. Whatever backend you have try to move to NSURL or URL as quickly as you can with any received data; it'll make your life easier and most importantly more consistent accross foundation API's.
moveItemAtURL - Foundation documentation
I use gzip library to convert data to gzip data
If I want to get string from data I do String(data: data, encoding: .utf8) . But if I do the same for gzip data I get nil string, because as far as I understand it's impossible to convert gzip data to string with .utf8 encoding.
I need that because I want to compare data with a server developer (because he sometimes he says that my data is incorrect format, but sometimes it's ok, and that's strange because I use the same library, and I have thoughts that may be the problem is on server side).
Is there any way to convert gzip data to any string to compare it then later?
If this is just for debug purpose, then I think the quickest way is:
let myGZipNSData = myGZipData as! NSData //I wrote a "!" just for the sample)
print("myGZipNSData: \(myGZipNSData)")
It should output:
myGZipNSData: <5b226d79 41727261 7956616c 75653022 2c226d79 41727261 7956616c 75653122 5d>
This relies on -description method of NSData which print "<hexValue>".
Do not rely on it on release version, almost never rely on -description (yes, Apple could change the behavior of -description in next release. It happened on a different class).
Other way (safer) to get almost the same result, you can check this question: How to convert Data to hex string in swift which you get you the same result (almost, less space, and no </>) as the previous one.
Other way: Base 64
Use base64EncodedString() method of Data:
let base64Str = myGZipData?.base64EncodedString()
print("base64Str: \(base64Str!)")
Output:
base64Str: WyJteUFycmF5VmFsdWUwIiwibXlBcnJheVZhbHVlMSJd
Now, there should be other way:
Have a array representation with Int values (between 0/255 instead of hex), but it seems to be for debug purpose so check if you can "reproduce the current solutions" (working/fast implementation) I gave you, and check with the server developer what he/she can do on his/her side too to compare.
Note:
For the purpose of this sample, myGZipData is constructed this way:
let array = ["myArrayValue0", "myArrayValue1"]
let myGZipData = try? JSONSerialization.data(withJSONObject: array, options:[])
It's not really a GZipData, but the goal was to quickly have a Data object "big enough".
Im currently working on an iOS app that requires the parsing of a dictionary of words.
When I attempt to import the file and convert the contents to Strings I get an error on the let path:String = Bundle.main.path(forResource: "words", ofType: "txt")! line. The error is Thread 1: "EXC_BREAKPOINT(code=1,subcode=0x1002e11ec)"
Any help would be greatly appreciated.
NOTE: Screen shot of assets attached
let path:String = Bundle.main.path(forResource: "words", ofType: "txt")!
text = try! String(contentsOfFile: path, encoding: String.Encoding.utf8)
words = text.components(separatedBy: ("\n"))
Bundle path(forResource:ofType:) returns an optional String. You are force unwrapping the options. This crashes when the return value is nil.
It returns nil when there is actually no such file in your app's resource bundle.
You need to actually have a file named words.txt in your app's bundle. Make sure the filename case matches and make sure the file is selected for your target.
Generally you shouldn't force-unwrap optionals. It causes crashes. However, one can argue that the two force-unwraps in the code you posted will never crash once your app is working properly. The first one is only crashing because you have not yet properly put the file in your resource bundle. And the 2nd (try!) won't crash once your file is correct because you know it will be a valid text file in the given encoding.
Don't use a dataset. Just drag your txt file right into the file navigator.
To explain further, the error you're seeing is that you're using ! which says you're guaranteeing that a path for that resource exists in the bundle. Which it doesn't.
How can I write to an xml document in Swift? I have this code:
let content = "<tag>Example</tag>"
var error: NSError?
content.writeToFile(NSBundle.mainBundle().pathForResource("my_file", ofType: "xml")!, atomically: true, encoding: NSUTF8StringEncoding, error: &error)
But this does not update the file in my Xcode project or on the device. How can I get this to work?
To collect all the fragments provided in comments into one place:
The app bundle is read-only on iOS. You can't save to it. It isn't forced to be read-only on Mac OS, but you should still treat it as such. As a result of this difference, code that modifies the app bundle may work on the simulator, but fail on an actual device.
You should save your contents to a file in the user's documents directory or one of the other sandbox directories. That code might look like this:
let docsPath = NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory.DocumentDirectory,
NSSearchPathDomainMask.UserDomainMask,
true)[0] as! NSString
let filePath = docsPath.stringByAppendingPathComponent("myfile")
let content = "<tag>Example</tag>"
var error: NSError?
content.writeToFile(filePath,
ofType: "xml",
atomically: true,
encoding: NSUTF8StringEncoding,
error: &error)
Then you should add error-checking that checks the bool result of the writeToFile command. If the result is false, check the error to see what went wrong.
Note that there is built-in support in iOS for reading XML, and quite a few third party libraries for saving collections of objects in XML format. You should take a look at NSXMLParser for reading. I can't really recommend one of the XML writing libraries over the others.
If you aren't wedded to XML, you might take a look at JSON. It's more compact, easier to write, easier to read, less memory-intensive, and there is built-in system support for both reading and writing Cocoa data structures from/to JSON files.