Fixed size array in swift - ios

i have a fixed size array as
var fieldNameArray = [String?](count: 4, repeatedValue: nil)
i am doing this to search if there is the element in array or not
if let temp = find(fieldNameArray,"profile_picture"){//i get a compile error here
//remove the data
....
}else{
println(" //append the value")
.....
}
But i get a compile time error as
Cannot invoke 'find' with an argument list of type '([(String?)],
String)'
I think i should unwrap it? How can i do it
UPDATED
SRWebClient.POST(registerURl)
.data(registerImagesArray, fieldName: fieldNameArray, data: parametersToPost)
.send({(response:AnyObject!, status:Int) -> Void in//here compile time error
println("response object: \(response)")
Again after i changed my array to fixed size array i got this error
Cannot invoke 'send' with an argument list of type '((AnyObject!, Int)
-> Void, failure: (NSError!) -> Void)

For efficiency you should not do what Manav Gabhawala suggests but write a find function yourself:
func myFind(array: [String?], value: String) -> Int? {
for (i, av) in enumerate(array) {
if av != nil && av! == value {
return i
}
}
return nil;
}
As Swift compiles to machine code, you will have nearly the same performance as with the standard library’s find.

Try using this instead (Swift 2.0):
if let index = fieldNameArray.indexOf("profile_picture") {
//remove the data using the index
....
} else {
print("// append the value")
.....
}
In swift 1.2 (a little inefficient but it works) :
if let temp = find(fieldNameArray.filter { $0 != nil}.map { $0! },"profile_picture") {
// Then same code as question...

Related

Error handling with assert

Suppose I have a class.
I want to give an error in init if my class doesn't follow the described rule
class Puzzle {
var puzzle_array: [Int]
var zero_index: Int
public init(array: [Int]) {
assert(array.count == 9, "Array should be lenght 9")
assert(array.index(of: 0) != nil, "There should ne 0 in array")
puzzle_array = array
zero_index = puzzle_array.index(of: 0)!
}
}
Then I need to create several instances of this class in a loop. Some of them, won't satisfy the condition, I described in init and complier and I will get an error.
But what I want is to skip creation of this instances without executing an error. And I want to keep checking condition logic inside init.
My initial idea might be wrong, but I'll appreciate if you help me to make it more properly.
You could use a failable initialiser to accomplish this, your object will be nil if you don't satisfy your checks.
class Puzzle {
var puzzle_array: [Int]
var zero_index: Int
public init?(array: [Int]) {
guard array.count == 9, array.index(of: 0) != nil else {
return nil
}
puzzle_array = array
zero_index = puzzle_array.index(of: 0)!
}
}
I disagree with #colmg that you should use failable initialiser, because it's destroys information about what actually went wrong.
Instead you should use throwable initalizer:
class Puzzle {
var puzzle_array: [Int]
var zero_index: Int
public init(array: [Int]) throws {
try assert(array.count == 9, "Array should be lenght 9")
try assert(array.index(of: 0) != nil, "There should ne 0 in array")
puzzle_array = array
zero_index = puzzle_array.index(of: 0)!
}
}
Assuming that assert is not standard version here, but this function:
struct AssertError: Error {
let description: String
}
func assert(_ condition: #autoclosure () -> Bool, _ description: String) throws {
if !condition() {
throw AssertError(description: description)
}
}
Now you can do this:
do {
let puzzle = try Puzzle([0, 1, 2, 3, 4])
} catch let error {
// Here you can handle error, and see what exactly went wrong, instead of just knowing that initialisation failed
}
Or you can use more advanced version:
func assert(_ condition: #autoclosure () -> Bool, _ error: Error) throws {
if !condition() {
throw error
}
}
class Puzzle {
var puzzle_array: [Int]
var zero_index: Int
public init(array: [Int]) throws {
try assert(array.count == 9, PuzzleError.invalidArrayLength)
try assert(array.index(of: 0) != nil, PuzzleError.arrayContainsZero)
puzzle_array = array
zero_index = puzzle_array.index(of: 0)!
}
enum PuzzleError: Error {
case invalidArrayLength
case noZeroInArray
}
}

how to convert [NSManagedObject] to nsmutable array (Swift)

i am using coredata in my app. i am storing 50 city in my core data. now i want to use search bar. which was working well with array. and i am using filtering for that. here is my code for that
arrcity.enumerateObjectsUsingBlock({ (obj, _, _) -> Void in
if let city : SelectCityModel = obj as? SelectCityModel
{
if city.city.lowercaseString.rangeOfString(self.searchtext.lowercaseString) != nil
{
self.searchcity?.addObject(city)
}
}
})
now i want to do same process but i have [nsmanagedobject] people. so how can i do this. it will be ease if is there any way to convert [NsmanagedObject] to nsmutablearry.
here is my code
if (people.count > 0)
{
people.enumerateObjectsUsingBlock({ (obj, _, _) -> Void in
if let city : SelectCityModel = obj as? SelectCityModel
{
if city.city.lowercaseString.rangeOfString(self.searchtext.lowercaseString) != nil
{
self.searchcity?.addObject(city)
}
}
})
}
but here var people = NSManagedObject so how can i convert it?
NSMutableArray is not related to a Swift Array.
But you could use the Swift Array with a native enumerator, for example
people.forEach { [unowned self] (object) -> () in
if object is SelectCityModel
{
if object.city.lowercaseString.rangeOfString(self.searchtext.lowercaseString) != nil
{
self.searchcity?.addObject(city)
}
}
}
If people is always [SelectCityModel] cast it to that type in the fetch line and omit the type check in the forEach closure. The check if people > 0 is not needed either.
A more convenient way is to use the filter and map functions.
self.searchcity = people.filter({$0.city.lowercaseString.rangeOfString(self.searchtext.lowercaseString) != nil}).map{ $0.city }

Intermittent fatal error (unexpectedly found nil while unwrapping an Optional value) in Swift

This error is intermittent. Sometimes the app works fine and sometimes it does not.
I have a view controller getNamesViewController which has an alamofire request, it also has a scroll view that loads extra nibs to allow the user to scroll left or right through the content
The results from alamofire are passed to each of the views like so:
self.vc0.a = self.a
where vc0 has been declared as the xib:
let vc0 = displayRegionsViewController(nibName: "displayRegionsViewController", bundle: nil)
The alamofire that gets the results and passes them to the variables is:
Alamofire.request(.GET, url, parameters: ["api_key": api])
.responseJSON { response in
switch response.result {
case .Success:
if let value = response.result.value {
let json = JSON(value)
dispatch_async(dispatch_get_main_queue()) {
self.a = json["totalCountName"].stringValue
self.b = json["namesRegion"].stringValue
self.vc0.a = self.a
self.vc0.b = self.b
}
}
case .Failure(let error):
print(error)
}
}
This data gets values from the JSON (The JSON returns 0 if there are no results)
On the nib file, The variables are initialized like so:
var a:Int? = 0
var b:Int? = 0
var c:Float? = 00.0
var d:Float? = 00.0
Then in the view did load, I have this code:
func percentageSum (lhs: Int, rhs: Int) -> String {
let result = round((Double(lhs) / Double(rhs)) * 100)
return String(result) + "%"
}
func percentageSumFloat (lhs: Float, rhs: Float) -> Float {
let floatreturn = Float((lhs / rhs) * 100)
print(floatreturn)
return floatreturn
}
//Convert passed value to int
a = Int(a)
b = Int(b)
if (a != 0) && (b != 0) {
self.displayViewsTotal.text = percentageSum(self.a!,rhs: self.b!)
campaignOpensTotalChart.updateProgressCircle(percentageSumFloat(c!,rhs: d!))
campaignOpensTotalChart.changeLineWidth(CGFloat(20))
SwiftSpinner.hide()
}else {
SwiftSpinner.show("Unexpected Error, Try again").addTapHandler({
SwiftSpinner.hide({
self.initRun()
})
}, subtitle: "Tap to try again..")
}
Now, as I said sometimes (More than not) This works, but every now and then (more on actual device) I get the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
At Xcode highlights this line:
self.displayViewsTotal.text = percentageSum(self.a!,rhs: self.b!)
Confession:
I am a noob at this, trying to get straight into development by building an app.
This is what I want:
Use alamofire to connect to the JSON API and get the results (Which are String Form)
Once alamofire is complete, pass those new values to variables declared in the nib files which are loaded in the scroll view.
or, if the way I am doing it so far is acceptable, I would simply like a way to make this code:
self.displayViewsTotal.text = percentageSum(self.a!,rhs: self.b!)
campaignOpensTotalChart.updateProgressCircle(percentageSumFloat(c!,rhs: d!))
campaignOpensTotalChart.changeLineWidth(CGFloat(20))
not throw the error above.
Please help me guys, I am bashing my head against the wall here.
Edit: Thoughts
I think it might be wither something to do with the view getting loaded before alamofire has loaded the data, however I used:
dispatch_async(dispatch_get_main_queue()) { }
which I believe fixes that issue?
If you're not sure your optionals are not nil, don't force wrap them like self.displayViewsTotal.text = percentageSum(self.a!,rhs: self.b!)
Just rewrite your code and check your optionals are not nil before using.
func percentageSum (lhs: Int?, rhs: Int?) throws -> String {
guard let lhs = lhs else{
return "lhs is nil"
}
guard let rhs = rhs else{
return "rhs is nil"
}
let result = round((Double(lhs) / Double(rhs)) * 100)
return String(result) + "%"
}
self.displayViewsTotal.text = percentageSum(self.a,rhs: self.b)

Convert array of custom object to AnyObject in Swift

In my app I am doing something like this:
struct Record {
var exampleData : String
}
class ExampleClass : UIViewController {
let records = [Record]()
override func viewDidLoad() {
super.viewDidLoad()
let data = NSKeyedArchiver.archivedDataWithRootObject(self.records) as! NSData
}
...
}
But in the last line of viewDidLoad() I got this error:
Argument type '[Record]' does not conform to expected type 'AnyObject'
How can I fix this? Thanks.
If you want to keep struct, you can encode data using withUnsafePointer(). Here's an example, which I adapted from this Gist:
import UIKit
enum EncodingStructError: ErrorType {
case InvalidSize
}
func encode<T>(var value: T) -> NSData {
return withUnsafePointer(&value) { p in
NSData(bytes: p, length: sizeofValue(value))
}
}
func decode<T>(data: NSData) throws -> T {
guard data.length == sizeof(T) else {
throw EncodingStructError.InvalidSize
}
let pointer = UnsafeMutablePointer<T>.alloc(1)
data.getBytes(pointer, length: data.length)
return pointer.move()
}
enum Result<T> {
case Success(T)
case Failure
}
I added some error handling and marked the method as throws. Here's one way you can use it, in a do…catch block:
var res: Result<String> = .Success("yeah")
var data = encode(res)
do {
var decoded: Result<String> = try decode(data)
switch decoded {
case .Failure:
"failure"
case .Success(let v):
"success: \(v)" // => "success: yeah"
}
} catch {
print(error)
}
The error handling I added will not decode if the NSData length doesn't match the type size. This can commonly happen if you write the data to disk, the user updates to a newer version of the app with a different-sized version of the same type, and then the data is read in.
Also note that sizeof() and sizeofValue() may return different values on different devices, so this isn't a great solution for sending data between devices (NSJSONSerialization might be better for that).
AnyObject means any reference type object, primarily a class. A struct is a value type and cannot be passed to a function needing an AnyObject. Any can be used to accept value types as well as reference types. To fix your code above, change struct Record to class Record. But I have a feeling you may want to use a struct for other reasons. You can create a class wrapper around Record that you can convert to and from to use for functions that need an AnyObject.
I did a similar thing:
static func encode<T>(value: T) -> NSData {
var val = value
return withUnsafePointer(to: &val) { pointer in
NSData(bytes: pointer, length: MemoryLayout.size(ofValue: val))
}
}
static func decode<T>(data: NSData) -> T {
guard data.length == MemoryLayout<T>.size.self else {
fatalError("[Credential] fatal unarchiving error.")
}
let pointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
data.getBytes(pointer, length: data.length)
return pointer.move()
}

Cannot invoke 'split' with an argument list of type '(String, (String) -> Bool)'. Swift 2

I am currently facing the following problem with a program that I am using to learn Swift and OAuth with: https://github.com/soundcloud/iOSOAuthDemo.
The error is as follows:
Cannot invoke 'split' with an argument list of type '(String, (String) -> Bool)'
with this snippet:
private func parameterValue(name: String, fragment: String) -> String? {
let pairs = split(fragment) { $0 == "&" }.filter({ pair in pair.hasPrefix(name + "=") })
if pairs.count > 0 {
return split(pairs[0]) { $0 == "=" }[1]
} else {
return nil
}
}
The guidance is:
Expected an argument list of type '(S, maxSplit: Int, allowEmptySlices: Bool, isSeparator: #noescape (S.Generator.Element) -> R)'
Is there anyone who may be help me to remove this error, as I am new to Swift and Swift 2.0?
Thanks In Advance,
The main idea with this duplicate link was to show you that in Swift 2 String is not a collection anymore, you have to use the String's characters property (and split is not a global function anymore). You also have to make some types back to String. Example:
private func parameterValue(name: String, fragment: String) -> String? {
let pairs = fragment.characters.split { $0 == "&" }.filter({ pair in String(pair).hasPrefix(name + "=") })
if pairs.count > 0 {
let subseq = pairs[0].split { $0 == "=" }.map { String($0) }
return subseq[1]
}
return nil
}
parameterValue("mike", fragment: "&mike=test") // "test"
Note that instead you could use the String's componentsSeparatedByString method to make your function look a bit simpler:
private func parameterValue(name: String, fragment: String) -> String? {
let pairs = fragment.componentsSeparatedByString("&").filter { $0.hasPrefix(name + "=") }
if !pairs.isEmpty {
return pairs[0].componentsSeparatedByString("=")[1]
}
return nil
}
parameterValue("mike", fragment: "&mike=test") // "test"

Resources