Converting objective-c codes to swift 4 - ios

it's been 1.5 years i've been writing in obj-c, its a good language.. so i saw a medium article today about swift, really looking onto it, right now i am trying to convert all my obj-c codes to swift, fortunately everything is done expect for this part..
NSString *path = [[NSBundle mainBundle] pathForResource:#"list" ofType:#"plist"];
NSArray *plistData = [NSArray arrayWithContentsOfFile:path];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"english ==[c] %#", self.userQuery.text]; // something like "Abbey"
NSArray *filtered = [plistData filteredArrayUsingPredicate:filter];
NSLog(#"found matches: %# : %#", filtered,[filtered valueForKey:#"kurdi"]);
if (filtered.count>0) {
NSDictionary *dic = filtered[0];
self.theMeaningLabel.text = dic[#"kurdi"];
} else {
self.theMeaningLabel.text = #"Yay!‌";
}
i am not being able to properly convert this into the new swift 4, it gives random errors
EDIT
after a few searches, i could just write two lines of code
here's my swift code
var path: String? = Bundle.main.path(forResource: "list", ofType: "plist")
var plistData = [Any](contentsOfFile: path!)
var filter = NSPredicate(format: "english ==[c] %#", searchText)
// something like "Abbey"
var filtered = plistData?.filter { filter.evaluate(with: $0) }
print("found matches: \(filtered) : \(filtered?.value(forKey: "kurdi"))")
if filtered?.count > 0 {
var dic = filtered[0]
// theMeaningLabel.text = dic["kurdi"]
}
else {
//theMeaningLabel.text = "Yay!‌"
}
but getting the
Argument labels '(contentsOfFile:)' do not match any available overloads
Final edit
var path = Bundle.main.path(forResource:"list", ofType: "plist")
var plistData = NSArray(contentsOfFile: path!)
let filter = NSPredicate(format: "english ==[c] %#", searchText)
var filtered = plistData?.filtered(using: filter)
// [error 9:10] no viable alternative at input 'NSLog(#"found matches: %# : %#"'
if filtered?.count > 0 {
var dic = filtered![0]
// theMeaningLabel.text = dic["kurdi"]
}
else {
// theMeaningLabel.text = "Yay!‌"
}
the code above is fine, but one error comes
if filtered?.count > 0 { // here
var dic = filtered![0]
// theMeaningLabel.text = dic["kurdi"]
}
else {
// theMeaningLabel.text = "Yay!‌"
}
getting
Binary operator '>' cannot be applied to operands of type 'Int?' and 'Int'

A literal translation from Objective-C to Swift is not recommended because in many cases it does not take advantage of the improved semantics of Swift.
As Apple removed all path manipulating API from String and added more URL related API to other classes use always URL if possible
let url = Bundle.main.url(forResource: "list", withExtension: "plist")!
The forced unwrapped url is safe since the file is required to be in the bundle. A crash will reveal a design error and must not happen at runtime.
Unlike the Foundation collection types the Swift collection types don't support the implicit property list conversion so the Swift way is to use Data and PropertyListSerialization
let data = try! Data(contentsOf: url)
let dataArray = try! PropertyListSerialization.propertyList(from: data, format: nil) as! [Any]
The forced try! is as safe as forced unwrapping the url for the same reasons.
[Any] is the most unspecified Swift Array. If the array is supposed to be an array of dictionaries write [[String:Any]] or even [[String: String]] if all values are String. If it's supposed to be an array of Strings write [String]. Swift encourages the developer to be as type specific as possible.
An NSPredicate can be replaced with the filter function in Swift. For example an array of strings can be filtered case insensitively with
let filtered = dataArray.filter { $0.compare(searchText, options:.caseInsensitive) == .orderedSame }
If the array contains dictionaries you need to specify the keys (same as NSPredicate)
let filtered = dataArray.filter { ($0["foo"] as! String).compare(searchText, options:.caseInsensitive) == .orderedSame }
Finally the ObjC expression
if (filtered.count > 0) { ...
can be written much more descriptive in Swift
if filtered.isEmpty == false { ...
or
if !filtered.isEmpty { ...
If you are looking for only one item you can even write
if let foundObject = dataArray.first(where: { $0.compare(searchText, options:.caseInsensitive) == .orderedSame }) { ...

Related

How to filter String array in Swift

By using objective C I have filter year array by using NSPredicate,
Below is code.
yearArray = [yearArray filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:#"SELF != ''"]];
As per above code it's working fine in objective c , I have to filter array in Swift 3,
What is Input Year Array :-
( Year,"","","",JAN,"","","",FEB,"","","",MAR,"","","",APR,"","","",
MAY,"","","",JUN,"","","",JUL,"","","",AUG,"","","",SEP,"","","",OCT
,"","","", NOV,"","","",DEC,"","","","",WIN,"","","",SPR,"","","",SUM
,"","","",AUT,"","","","",ANN)
Need filter Output Array
(Year,JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC,WIN,SPR,SUM,AUT,ANN)
Please give solution how to filter array in swift.
Use this code:
let yearArray: [String] = ... // your array of type [String]
let filteredArray = yearArray.filter {
!$0.isEmpty
}
Look at the picture for output:
You can do it by using filter (on an Array type) :
let filteredArray = yearArray.filter{$0 != ""}
It's that simple.
If your array is an NSMutableArray, just cast it to [String] :
if let yearArray = yearArray as? [String] {
let filteredArray = yearArray.filter{$0 != ""}
// add your code here
}

Check if an array of CKRecords contains a certain record

In my app I have got hundreds of movie objects as CKRecords that is being put in an array after retrieving them. I would, for example, like a way to check if the array contains a movie record with the title "Titanic".
What I have done up till now, is looping trough the array like this:
for movie in (movies as NSArray as! [CKRecord]) {
if movie.objectForKey("Title") as? String == "Titanic" {
// Do stuff
}
}
But what I want is something like this:
if movies.contains(CKRecord.whereKey"Title" == "Titanic") {
// Do stuff
}
You have to use a filter in the array, for example:
let filteredArray = movies.filter() {
if let title = ($0 as PFObject)["Title"] as String {
return type.rangeOfString("example") != nil
} else {
return false
}
}
There are 2 ways we can proceed with this:
1 Approach: Using NSpredicate
let predicate = NSPredicate(format: "Title = 'Titanic'")
let movie = (movies as NSArray).filteredArrayUsingPredicate(predicate) as! NSArray
Then we can check the count of array for presence of object.
Using Filter function as give by #Exequiel above

Swift filter array of strings

I've had troubles filtering array of keywords (strings) in swift ,My code:
self.filteredKeywords=filter(keywords.allValues, {(keyword:NSString) ->
Bool in
let words=keyword as? NSString
return words?.containsString(searchText)
})
As AnyObject can't be subtype of NSString, I'm stuck with this!
[Updated for Swift 2.0]
As NSString is toll-free bridged to Swift String, just avoid the coercions with:
3> ["abc", "bcd", "xyz"].filter() { nil != $0.rangeOfString("bc") }
$R1: [String] = 2 values {
[0] = "abc"
[1] = "bcd"
}
But, if you think allValues aren't strings:
(keywords.allValues as? [String]).filter() { nil != $0.rangeOfString("bc") }
which returns an optional array.
Your filter is over [AnyObject], but your closure takes NSString. These need to match. Also, your result needs to be a Bool, not a Bool?. You can address these simply like this:
self.filteredKeywords = filter(keywords.allValues, {
let keyword = $0 as? NSString
return keyword?.containsString(searchText) ?? false
})
This accepts AnyObject and then tries to coerce it down to NSString. It then nil-coalleces (??) the result to make sure it always is a Bool.
I'd recommend, though, treating keywords as a [String:String] rather than an NSDictionary. That would get rid of all the complications of AnyObject. Then you can just do this:
self.filteredKeywords = keywords.values.filter { $0.rangeOfString(searchText) != nil }
Whenever possible, convert Foundation collections into Swift collections as soon as you can and store those. If you have incoming Foundation objects, you can generally convert them easily with techniques like:
let dict = nsdict as? [String:String] ?? [:]
Or you can do the following to convert them such that they'll crash in debug (but silently "work" in release):
func failWith<T>(msg: String, value: T) -> T {
assertionFailure(msg)
return value
}
let dict = nsdict as? [String:String] ?? failWith("Couldn't convert \(d)", [:])
Swift 4.2 provides a new way to do this:
var theBigLebowski = ["The Dude", "Angry Walter", "Maude Lebowski", "Donny Kerabatsos", "The Big Lebowski", "Little Larry Sellers"]
// after removeAll -> ["The Dude", "Angry Walter", "Donny Kerabatsos", "Little Larry Sellers"]
theBigLebowski.removeAll{ $0.contains("Lebowski")}
print(theBigLebowski)
There is both a problem with GoZoner's answer for certain data types and also a slightly better way to do this. The following examples can show this:
let animalArray: NSMutableArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.rangeOfString("er") != nil }
print("filteredAnimals:", filteredAnimals)
filteredAnimals: [Dog, Cat, Otter, Deer, Rabbit]
Likely not the set you expected!
However this works fine this way if we don't type animalArray as an NSMutableArray:
let animalArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.rangeOfString("er") != nil }
print("filteredAnimals:", filteredAnimals)
filteredAnimals: [Otter, Deer]
However I'd recommend using $0.contains() instead of $0.rangeOfString() != nil because it functions in both circumstances and slightly enhances the readability of the code:
let animalArray: NSMutableArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.contains("er") }
print("filteredAnimals:", filteredAnimals)
filteredAnimals: [Otter, Deer]

How can I access the values in this NSDictionary in Swift?

I am trying to access the 'address' object (String) in a dictionary:
Chain.sharedInstance().getAddress("19b7ZG3KVXSmAJDX2WXzXhWejs5WS412EZ"){ dictionary, error in
NSLog("%#", dictionary)
let value = dictionary["address"] as? String //returns nil
}
this is the data I receive:
results = (
{
address = 19b7ZG3KVXSmAJDX2WXzXhWejs5WS412EZ;
confirmed = {
balance = 0;
received = 20000000;
sent = 20000000;
};
total = {
balance = 0;
received = 20000000;
sent = 20000000;
};
}
); }
How do I access the values in this dictionary when I keep getting nil?
To clarify, the data you are posting is not JSON, but rather looks like JSONP. You aren't showing any code deserializing the the object, so I assume Chain.sharedInstance().getAddress is handling that aspect. If this is an instance of the Bitcoin API, you might look at their documentation. If it is their API, the documentation says the return is
A dictionary with a single "results" key, whose value is a array
containing a single Address Object as a dictionary.
If that is the case if would be
if let resultsArray = dictionary["results"] as NSArray {
if let dict = results[0] as NSDictionary {
//dict["address"] should have your address
}
}
Try:
if let dict = dictionary["results"] as NSDictionary
{
let value = dict["address"] as NSString
}
or:
if let dict = dictionary["results"] as NSArray
{
if let di = dict[0] as NSDictionary
{
let value = di["address"] as NSString
}
}

Core Data - Iterating through the attributes of a NSManagedObject

I am a noob at core data, so here goes.
I have a core data object, for example student.
The student has mane attributes, like name, age, dob, address, and so on.
Now I need to display all these attributes into a table view.
Is there any easy way to iterate through the object student? Or do I have to convert the data into some type of dictionary?
If I need to convert it to a dictionary is there any support for it? Or do I have to write the function my self.
Many thanks for your help,
Stephen
Here's a very simple way to iterate over an NSManagedObject:
NSEntityDescription *entity = [myManagedObject entity];
NSDictionary *attributes = [entity attributesByName];
for (NSString *attribute in attributes) {
id value = [myManagedObject valueForKey: attribute];
NSLog(#"attribute %# = %#", attribute, value);
}
The clues for how to do this (plus lots more) comes from Ole Bergmann's blog: http://oleb.net/blog/2011/05/inspecting-core-data-attributes/
If you are like me and are trying to solve this problem in Swift here is how I did it.
SWIFT 3:
let request:NSFetchRequest<ENTITY_NAME>
if #available(iOS 10.0, *){
request = ENTITY_NAME.fetchRequest() as! NSFetchRequest<ENTITY_NAME>
}else{
request = NSFetchRequest<ENTITY_NAME>(entityName: "ENTITY_NAME")
}
do{
let entities = try YOUR_MOC.fetch(request)
for item in entities{
for key in item.entity.attributesByName.keys{
let value: Any? = item.value(forKey: key)
print("\(key) = \(value)")
}
}
}catch{
}
Swift 2:
let request = NSFetchRequest(entityName: "ENTITY_NAME")
do{
let entities = try YOUR_MOC.executeFetchRequest(request) as! [YOUR_ENTITY]
for item in entities{
for key in item.entity.attributesByName.keys{
let value: AnyObject? = item.valueForKey(key)
print("\(key) = \(value)")
}
}
}catch{
}
If you want to get relationship entities key/values as well then you should use propertiesByName instead of attributesByName like so:
SWIFT 3:
for key in item.entity.propertiesByName.keys{
let value: Any? = item.value(forKey: key)
print("\(key) = \(value)")
}
SWIFT 2:
for key in item.entity.propertiesByName.keys{
let value: AnyObject? = item.valueForKey(key)
print("\(key) = \(value)")
}
Just remember to be careful with the value since it is an NSManagedObject.

Resources