self.coreDataStack.finalizeStatusForAccount(currentAccount, fromStatus: ObjectStatus.tempClear, toStatus: ObjectStatus.clear)
self.coreDataStack.finalizeStatusForAccount(currentAccount, fromStatus: ObjectStatus.tempGreen, toStatus: ObjectStatus.green)
I'm getting these two warnings can anyone please suggest how to remove these warnings
The warning says that the function finalizeStatusForAccount returns a value yet you don’t use it. You might want to assign the return value to a variable, like this:
let returnValue = self.coreDataStack.finalizeStatusForAccount...
Or if you know you don’t need to check the return value you would write this:
let _ = self.coreDataStack.finalizeStatusForAccount...
The latter is a standard pattern in Swift.
If this is your function finalizeStatusForAccount you can add #discardableResult this way:
#discardableResult
func finalizeStatusForAccount() -> Any {
return 100500
}
Related
I'm working in Swift and one of the protocols I'm using needs to return an UnsafeMutablePointer<T> of a particular object.
I have something like this:
#objc var myProperty:UnsafeMutablePointer<someObject>
{
get
{
// I call a class function here to get a 'someObject'
// return object which I need to pass back a pointer to it.
return UnsafeMutablePointer<someObject>
}
}
The problem is that Xcode doesn't like this. It complains that '>' is not a unary operator.
I've also tried removing the UnsafeMutablePointer<> and use an & in front of someObject but it complains that the & is to be used immediately in a list of arguments for a function.
I suppose I just can't find the right syntax for this? Any help would be appreciated.
If someObject has the type SomeClass, then you need to update your declaration like this:
#objc var myProperty:UnsafeMutablePointer<SomeClass>
{
get
{
return UnsafeMutablePointer<SomeClass>(unsafeAddressOf(someObject))
}
}
The generic argument needs to be the type of the returned data, and you also need to intialize a specialized UnsafeMutablePointer with the memory address of the desired object.
I am trying to get the result of a method of an existing Objective C class, called using performSelector
let result = controlDelegate.performSelector("methodThatReturnsBOOL") as? Bool
I need to cast this result to Bool type of Swift.
The code mentioned above, gives a warning
"Cast from 'Unmanaged!' to unrelated type 'Bool' always fails"
and the result is always "false", even when the method returns YES.
Any suggestions for converting the result to Bool ?
Signature for methodThatReturnsBOOL
- (BOOL)methodThatReturnsBOOL
{
return YES;
}
It's been a long time since this has remained unanswered so I'm adding what I have learned along the way.
To convert a BOOL value returned by an Objective C method you can simply cast it using,
if let result = controlDelegate.performSelector("methodThatReturnsBOOL") {
print("true")
} else {
print("false")
}
Here you can also assign the value true/false to a Swift Bool, if required.
Note : I tried casting Unmanaged<AnyObject> directly to Bool using takeRetainedValue() as suggested by many answers on SO, but that doesn't seem to work in this scenario.
You can't do what you want nicely in Swift. My issue with the accepted solution is that it takes advantage of the idea that 0x0 just so happens to be nil. This isn't actually guaranteed by Swift and Objective-C specifications. The same applies to boolean values since 0x0 being false and 0x1 being true is just an arbitrary implementation decision. Aside from being technically incorrect, it's also just awful code to understand. Without thinking about what a nil pointer is on most platforms (32/64 bits of zeros), what was suggested makes zero sense.
After talking to an engineer at WWDC '19 for a while, he suggested that you can actually use valueFor(forKey:) with the key being the function name/selector description. This works since the Obj-C runtime will actually execute any function with the given name/key in order to evaluate the expression. This is still a bit hacky since it requires knowledge of the Objective-C runtime, however it is guaranteed to be platform and implementation independent because valueFor(forKey:) returns an Any? which can be cast into an Int or a Bool without any trouble at all. By using the built in casts instead of speculating on what 0x0 or 0x1 means, we avoid the whole issue of interpreting a nil pointer.
Example:
#objc func doThing() -> Bool{
return true
}
...
let target = someObjectWithDoThing
let selectorCallResult = target.value(forKey: "doThing")
let intResult = selectorCallResult as? Int //Optional<Int(1)>
let boolResult = selectorCallResult as? Bool //Optional<Bool(true)>
This is the solution in Swift 3, as the methods are a bit different. This method also checks if Objective-C object responds to selector, to avoid crashing.
import ObjectiveC
let selector = NSSelectorFromString("methodThatReturnsBOOL")
guard controlDelegate.responds(to: selector) else {
return
}
if let result = controlDelegate.perform(selector) {
print("true")
}
else {
print("false")
}
Similarly to my answer here this can be done with #convention(c) instead:
let selector: Selector = NSSelectorFromString("methodThatReturnsBOOL")
let methodIMP: IMP! = controlDelegate.method(for: selector)
let boolResult: Bool = unsafeBitCast(methodIMP,to:(#convention(c)(Any?,Selector)->Bool).self)(controlDelegate,selector)
This^ particular syntax is available since Swift 3.1, also possible with one extra variable in Swift 3.
More compact cast to bool:
let result = controlDelegate.perform(NSSelectorFromString("methodThatReturnsBOOL")) != nil
I want to run different functions depending on selected level Integer
so if selected level is 1 then runfunc1(), if 2 then runfunc2()...
I know this is possible using if else
if levelselected == 1 {
runfunc1()
} else if levelseletecd == 2 {
runfunc2()
// ... and so on
}
Is there any better way than this, perhaps something like this
runfunc%i(),levelselected // I know its not correct but something similar
I dont want to write new code for every level, so any better way?
You can use something like:
var levelSelected = 0 //
var selector = Selector("runFunc\(levelSelected)")
if self.respondsToSelector(selector) {
NSThread.detachNewThreadSelector(selector, toTarget: self, withObject: nil)
}
You could have an array or dictionary of functions. A dictionary might be nicer since the logic for checking if the level is valid is a lot simpler:
let funcs = [1: runfunc1, 2: runfunc2]
if let funcToRun = funcs[levelselected] {
funcToRun()
}
However, you won't be able to easily dynamically build a function name from strings and numbers without using #objc functionality.
(except in the sense that you could make the key to the dictionary a string of the function name, but you still have to build the dictionary using actual function names determined at compile time)
That said, you can add to the funcs variable from elsewhere in the code so it does mean to can "hook up" new levels without changing this dispatching logic.
Not the exact solution you are looking for but this can make it easier :
Declare an array of the desired functions:
var levelFunctions: [()->()] = [runfunc1, runfunc2, runfunc3]
This syntax declares an array of functions that have zero argument and return nothing. You initialize this array with the required function names and then execute the desired function using the levelselected variable:
levelFunctions[levelselected]() // Or levelselected-1 if the variable is not zero-based
EDIT:
As Airspeed Velocity mentioned in the comment and his answer you should make sure the level is in the array bounds.
I prefer to create a function, for example runFuncFromLevel::Int -> (() -> Void). runFuncFromLevel return a proper function that you need.
func runFuncFromLevel(level: Int) -> () -> Void
{
switch level
{
case 1: return runfunc1
case 2: return runfunc2
default: return {}
}
}
So, I just realize that break is only for loop or switch.
Here's my question: Is there a recommended way to break out of a block? For example:
func getContentFrom(group: ALAssetsGroup, withAssetFilter: ALAssetsFilter) {
group.enumerateAssetsUsingBlock { (result, index , stop) -> Void in
//I want to get out when I find the value because result contains 800++ elements
}
}
Right now, I am using return but I am not sure if this is recommended. Is there other ways? Thanks folks.
return is fine, block concept is similar to function, so returning is okay.
If you want to stop the current iteration of the enumeration, simply return.
But you say:
I want to get out when I find the value because result contains 800++ elements
So, that means that you want to completely stop the enumeration when you find the one you want. In that case, set the boolean value that the pointer points to. Or, a better name for that third parameter would be stop, e.g.:
func getContentFrom(group: ALAssetsGroup, withAssetFilter: ALAssetsFilter) {
group.enumerateAssetsUsingBlock() { result, index, stop in
let found: Bool = ...
if found {
//I want to get out when I find the value because result contains 800++ elements
stop.memory = true
}
}
}
For convenience, in a little experiment I am doing, I would like to extend Array to provide some app specific functionalities. This specific extension is not necessary best practice, but I am just curious about solving the Swift issues I am having.
Given a custom class Section, my extension (with partially extended closure) is:
extension Array {
func onlyFullSection() -> Array<Section> {
return self.filter {
(a:Section) -> Bool in
return a.isFullSection()
}
}
}
The error I get is: "T" is not a subtype of "Section".
I tried to fix it with all the sauces (changing types, casting, etc...) but still get similar errors.
This other variant:
extension Array {
func onlyFullSection() -> Array<Section> {
return (self as Array<Section>).filter {
(a:Section) -> Bool in
return a.isFullSection()
} as Array<Section>
}
throws: Cannot convert the expression's type 'Array<Section>' to type 'Array<Section>'
Any clue on what I am doing wrong? Thanks!
It is because you are extending T[] and not Section[]. That means that Int[] will also have your additional method. That might not be the best idea (since it will crash badly).
Swift currently does not allow you to extend a specialised generic type like Section[].
But if you really, really want to do it, here is one way to force a cast, use reinterpretCast, which Apple describes as follows
/// A brutal bit-cast of something to anything of the same size
func reinterpretCast<T, U>(x: T) -> U
You can use it like this:
extension Array {
func onlyFullSection() -> Section[] {
let sections : Section[] = reinterpretCast(self)
return sections.filter{ $0.isFullSection() }
}
}
But please don't.
The problem is that since the Array class is actually a generic Array<T>, you are extending Array<T>. And apparently you can't cast between generic types (i.e. <T> to <Section>), so I believe you'll have to make a new array and just push the appropriate objects into it.
17> extension Array {
18. func onlyFullSection() -> Array<Section> {
19. var ary = Array<Section>()
20. for s in self {
21. if (s as Section).isFullSection() {
22. ary.append(s as Section)
23. }
24. }
25. return ary
26. }
27. }
You could also create a helper method to convert between generic types for you, but in this instance that would just create an unnecessary temporary object.
Remember that the language is still heavily in flux so it's possible this will change. I think it's unlikely that we'll get the ability to cast between generic types, but I hope we'll at least be able to extend particular generics.