Using Class name as variable name in Swift - ios

I want to extend the UIView class by doing:
extension UIView {
var UIImage:UIImage {
get {
let image = ....
// ..... my code ....//
return image
}
}
}
I get the following compilation error:
'UIImage' used within its own type
Anyone knows how to make it work?
PS: I know I can simply use a different name, but that is not what I am asking here.

You need to qualify the property's type name with the package name:
extension UIView {
var UIImage: UIKit.UIImage {
let image = UIKit.UIImage()
// ..... my code ....//
return image
}
}

Related

Casting subclass from base class where subclass has generic in Swift

I have a base class type and a subclass type, where the subclass includes a generic type. If I have the subclass stored in the form of the base class type but I would like to type cast it back to the subclass type, Swift won't seem to let me.
Below is an example of what I mean:
class Base {
}
class Next<T> : Base where T : UIView {
var view: T
init(view: T) {
self.view = view
}
}
let a: [Base] = [Next(view: UIImageView()), Next(view: UILabel())]
for item in a {
if let _ = item as? Next {
print("Hey!")
}
}
Why is "Hey!" never printed?
EDIT:
"Hey!" is printed if the cast reads:
if let _ item as? Next<UIImageView> ...
but only for the case of the UIImageView class.
and
"Hey!" is printed if one of the items in the array a is:
Next(view: UIView())
Ideally, I would like to not know what type the generic is when casting, but I realise this may not be possible.
The generic Next<T> is a template of sorts that creates unique separate classes. Next<UIView> and Next<UIImageView> are two completely unrelated types.
You can unite them with a protocol:
class Base {
}
class Next<T> : Base where T : UIView {
var view: T
init(view: T) {
self.view = view
}
}
protocol NextProtocol { }
extension Next: NextProtocol { }
let a: [Base] = [Next(view: UIImageView()), Next(view: UILabel()), Base()]
for item in a {
if item is NextProtocol {
print("Hey!")
} else {
print("Only a Base")
}
}
Output:
Hey!
Hey!
Only a Base
By defining a protocol such as NextProcotol that all classes derived from Next<T> conform to, you can refer to them as a group and distinguish them from other classes that derive from Base.
Note: To check if an item is of a type, use is instead of checking if the conditional cast as? works.
This is where protocols comes to help.
you need a dummy protocol to confirm Next to it
And use that dummy protocol to check your items types.
Therefore we create a dummy protocol confirm Next to it and use that protocol to compare items.
code would be something like this.
class Base {
}
class Next<T> : Base where T : UIView {
var view: T
init(view: T) {
self.view = view
}
}
protocol MyType {
}
extension Next: MyType {}
let a: [Base] = [Next(view: UILabel()), Next(view: UILabel())]
for item in a {
if let _ = item as? MyType {
print("Hey!")
}
}
UIView is super class for all the UIElements.
saying this will result into true,
if let _ = UILabel() as? UIView {print("yes") }
Next does not confirm to UIView but rather it requires something that confirm to UIView therefore you can't use the subs of UIView to check if they are Next, next have no exact type,
here we use the dummy protocol above !
When I saw your example I was expecting it to fail during compilation.
It seems that as long as you specify a concrete base class for your T (in this case UIView), then the compiler can infer that class in as or is statements. So when you type item as? Next the compiler understands item as?Next` because UIView is a concrete type.
This would not work if instead of UIView you would use a protocol. Also, simply using Next instead of Next<UIView> (or Next<concrete subclass of UIView>) will result in a compiler error outside an is or as statement.

Setting a computed value (struct vs class)

I made a simple struct that handles the management of the UI background (the user can choose to use a gradient or image). Inside this struct is a computed property called preference which gets and sets the user's preference to UserDefaults.
When I try to set the preference property using the following code:
Background().preference = .gradient
I get an error: "Cannot assign to property: function call returns immutable value"
I have to use this instead:
var background = Background()
background.preference = .gradient
I would prefer not having to assign an instance of Background to a variable before finally setting the property.
I've found that changing Background from a struct to a class allows me to set the property using Background().preference = .gradient directly.
Can anyone give me some insight as to why this occurs? Is using class better than using struct for this situation or does it not matter?
struct Background {
enum Choice {
case gradient
case image
}
var preference: Choice {
get {
if let type = UserDefaults.standard.value(forKey: "background_type"), type as! String == "background" {
return .image
}
return .gradient
}
set(value){
if value == .image {
UserDefaults.standard.setValue("background", forKey: "background_type")
}else{
UserDefaults.standard.setValue("gradient", forKey: "background_type")
}
}
}
You're not really getting any value from making an instance of a struct / class to just wrap UserDefaults. It's a very common problem and there are lots of clever solutions out there on google if you search around. For a really simple example you could just extend UserDefaults
//: Playground - noun: a place where people can play
import Cocoa
enum BackgroundChoice {
case gradient
case image
}
extension UserDefaults {
var backgroundChoice: BackgroundChoice {
get {
if let type = string(forKey: "background_type"), type == "image" {
return .image
}
return .gradient
}
set(value){
if value == .image {
setValue("background", forKey: "background_type")
}else{
setValue("gradient", forKey: "background_type")
}
}
}
}
UserDefaults.standard.backgroundChoice = .image
I know this doesn't answer your exact question, but I think you'll find there are better solutions to this problem if you dig around.

How to create a new field in UITextField extension?

I am new to Swift and maybe it's a stupid question, but I can't find an answer to it.
I have created an extension:
extension UITextField {
var placeholderLabel: UILabel {
get {
return self.placeholderLabel
}
set {
self.placeholderLabel = newValue
}
}
}
When the property is set, the application crashes.
You can't have a stored property in extension.
Extensions are not allowed to add a property to existing class because adding a property structure of the class will change. And because Objective C, Swift or any other programming language that am aware of could not afford it, it won't allow you to add the stored property to extension.
Isn't there any work around then ??
This is what you can do to save the label as stored property in your extension :)
import Foundation
import UIKit
fileprivate var ascociatedObjectPointer : UInt8 = 99
extension UITextField {
var myLabel : UILabel {
get {
return objc_getAssociatedObject(self, &ascociatedObjectPointer) as! UILabel
}
set {
objc_setAssociatedObject(self, &ascociatedObjectPointer, myLabel, .OBJC_ASSOCIATION_RETAIN)
}
}
}
How it works ??
Simple by writing setter and getter for the variable which you are posing or pretending to be stored property and by internally holding a pointer which has nothing to do with the existing class, hence it won't affect the structure of existing class.
Hope it helps.
You can use NSMapTable like this:
extension UITextField {
private static var placeholderLabelMap: NSMapTable<UITextField, UILabel> = .weakToStrongObjects()
var placeholderLabel: UILabel? {
get {
return UITextField.placeholderLabelMap.object(forKey: self)
}
set {
UITextField.placeholderLabelMap.setObject(newValue, forKey: self)
}
}
}
The advantage of Sandeep's answer might be thread safety. You can see this Stack Overflow topic for comparison between the approaches.

What if I want to assign a property to itself?

If I attempt to run the following code:
photographer = photographer
I get the error:
Assigning a property to itself.
I want to assign the property to itself to force the photographer didSet block to run.
Here's a real-life example: In the "16. Segues and Text Fields" lecture of the Winter 2013 Stanford iOS course (13:20), the professor recommends writing code similar to the following:
#IBOutlet weak var photographerLabel: UILabel!
var photographer: Photographer? {
didSet {
self.title = photographer.name
if isViewLoaded() { reload() }
}
}
override func viewDidLoad() {
super.viewDidLoad()
reload()
}
func reload() {
photographerLabel.text = photographer.name
}
Note: I made the following changes: (1) the code was switched from Objective-C to Swift; (2) because it's in Swift, I use the didSet block of the property instead of the setPhotographer: method; (3) instead of self.view.window I am using isViewLoaded because the former erroneously forces the view to load upon access of the view property; (4) the reload() method (only) updates a label for simplicity purposes, and because it resembles my code more closely; (5) the photographer IBOutlet label was added to support this simpler code; (6) since I'm using Swift, the isViewLoaded() check no longer exists simply for performance reasons, it is now required to prevent a crash, since the IBOutlet is defined as UILabel! and not UILabel? so attempting to access it before the view is loaded will crash the application; this wasn't mandatory in Objective-C since it uses the null object pattern.
The reason we call reload twice is because we don't know if the property will be set before or after the view is created. For example, the user might first set the property, then present the view controller, or they might present the view controller, and then update the property.
I like how this property is agnostic as to when the view is loaded (it's best not to make any assumptions about view loading time), so I want to use this same pattern (only slightly modified) in my own code:
#IBOutlet weak var photographerLabel: UILabel?
var photographer: Photographer? {
didSet {
photographerLabel?.text = photographer.name
}
}
override func viewDidLoad() {
super.viewDidLoad()
photographer = photographer
}
Here instead of creating a new method to be called from two places, I just want the code in the didSet block. I want viewDidLoad to force the didSet to be called, so I assign the property to itself. Swift doesn't allow me to do that, though. How can I force the didSet to be called?
Prior to Swift 3.1 you could assign the property name to itself with:
name = (name)
but this now gives the same error: "assigning a property to itself".
There are many other ways to work around this including introducing a temporary variable:
let temp = name
name = temp
This is just too fun not to be shared. I'm sure the community can come up with many more ways to do this, the crazier the better
class Test: NSObject {
var name: String? {
didSet {
print("It was set")
}
}
func testit() {
// name = (name) // No longer works with Swift 3.1 (bug SR-4464)
// (name) = name // No longer works with Swift 3.1
// (name) = (name) // No longer works with Swift 3.1
(name = name)
name = [name][0]
name = [name].last!
name = [name].first!
name = [1:name][1]!
name = name ?? nil
name = nil ?? name
name = name ?? name
name = {name}()
name = Optional(name)!
name = ImplicitlyUnwrappedOptional(name)
name = true ? name : name
name = false ? name : name
let temp = name; name = temp
name = name as Any as? String
name = (name,0).0
name = (0,name).1
setValue(name, forKey: "name") // requires class derive from NSObject
name = Unmanaged.passUnretained(self).takeUnretainedValue().name
name = unsafeBitCast(name, to: type(of: name))
name = unsafeDowncast(self, to: type(of: self)).name
perform(#selector(setter:name), with: name) // requires class derive from NSObject
name = (self as Test).name
unsafeBitCast(dlsym(dlopen("/usr/lib/libobjc.A.dylib",RTLD_NOW),"objc_msgSend"),to:(#convention(c)(Any?,Selector!,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
unsafeBitCast(class_getMethodImplementation(type(of: self), #selector(setter:name)), to:(#convention(c)(Any?,Selector!,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
unsafeBitCast(method(for: #selector(setter:name)),to:(#convention(c)(Any?,Selector,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
_ = UnsafeMutablePointer(&name)
_ = UnsafeMutableRawPointer(&name)
_ = UnsafeMutableBufferPointer(start: &name, count: 1)
withUnsafePointer(to: &name) { name = $0.pointee }
//Using NSInvocation, requires class derive from NSObject
let invocation : NSObject = unsafeBitCast(method_getImplementation(class_getClassMethod(NSClassFromString("NSInvocation"), NSSelectorFromString("invocationWithMethodSignature:"))),to:(#convention(c)(AnyClass?,Selector,Any?)->Any).self)(NSClassFromString("NSInvocation"),NSSelectorFromString("invocationWithMethodSignature:"),unsafeBitCast(method(for: NSSelectorFromString("methodSignatureForSelector:"))!,to:(#convention(c)(Any?,Selector,Selector)->Any).self)(self,NSSelectorFromString("methodSignatureForSelector:"),#selector(setter:name))) as! NSObject
unsafeBitCast(class_getMethodImplementation(NSClassFromString("NSInvocation"), NSSelectorFromString("setSelector:")),to:(#convention(c)(Any,Selector,Selector)->Void).self)(invocation,NSSelectorFromString("setSelector:"),#selector(setter:name))
var localVarName = name
withUnsafePointer(to: &localVarName) { unsafeBitCast(class_getMethodImplementation(NSClassFromString("NSInvocation"), NSSelectorFromString("setArgument:atIndex:")),to:(#convention(c)(Any,Selector,OpaquePointer,NSInteger)->Void).self)(invocation,NSSelectorFromString("setArgument:atIndex:"), OpaquePointer($0),2) }
invocation.perform(NSSelectorFromString("invokeWithTarget:"), with: self)
}
}
let test = Test()
test.testit()
There are some good workarounds but there is little point in doing that.
If a programmer (future maintainer of the code) sees code like this:
a = a
They will remove it.
Such a statement (or a workaround) should never appear in your code.
If your property looks like this:
var a: Int {
didSet {
// code
}
}
then it's a not a good idea to invoke the didSet handler by assignment a = a.
What if a future maintainer adds a performance improvement to the didSet like this?
var a: Int {
didSet {
guard a != oldValue else {
return
}
// code
}
}
The real solution is to refactor:
var a: Int {
didSet {
self.updateA()
}
}
fileprivate func updateA() {
// the original code
}
And instead of a = a directly call updateA().
If we are speaking about outlets, a suitable solution is to force the loading of views before assigning for the first time:
#IBOutlet weak var photographerLabel: UILabel?
var photographer: Photographer? {
didSet {
_ = self.view // or self.loadViewIfNeeded() on iOS >= 9
photographerLabel?.text = photographer.name // we can use ! here, it makes no difference
}
}
That will make the code in viewDidLoad unnecessary.
Now you might be asking "why should I load the view if I don't need it yet? I want only to store my variables here for future use". If that's what you are asking, it means you are using a view controller as your model class, just to store data. That's an architecture problem by itself. If you don't want to use a controller, don't even instantiate it. Use a model class to store your data.
I hope one day #Swift developers will fix this miscuzzi :)
Simple crutch:
func itself<T>(_ value: T) -> T {
return value
}
Use:
// refresh
style = itself(style)
image = itself(image)
text = itself(text)
(optionals including)
Make a function that the didSet calls then call that function when you want to update something? Seems like this would guard against developers going WTF? in future
#vacawama did a great job with all those options. However in iOS 10.3, Apple banned some of these ways and most likely will be doing it in the future again.
Note: To avoid the risk and future errors, I will use a temporary variable.
We can create a simple function for that:
func callSet<T>(_ object: inout T) {
let temporaryObject = object
object = temporaryObject
}
Would be used like: callSet(&foo)
Or even a unary operator, if there is a fitting one ...
prefix operator +=
prefix func +=<T>(_ object: inout T) {
let temporaryObject = object
object = temporaryObject
}
Would be used like: +=foo

What's the Swift equivalent of declaring `typedef SomeClass<SomeProtocol> MyType`?

I’m currently writing some Swift code in a project that is predominately Objective-C. In our ObjC code, we have a header that declares typedef GPUImageOutput<GPUImageInput> MyFilter;. We can then declare e.g. a #property that can only be a GPUImageOutput subclass that implements GPUImageInput.
(NOTE: GPUImageOutput and GPUImageInput are not defined by me; they are part of the GPUImage library)
Our Swift code doesn't seem to recognize this, even though the header is #imported in our Bridging Header. I’ve tried to replicate the declaration in Swift, but neither of these are proper syntax:
typealias MyFilter = GPUImageOutput, GPUImageInput
typealias MyFilter = GPUImageOutput : GPUImageInput
You can't declare typealias like that.
The best we can do is something like this:
class MyClass {
private var filter:GPUImageOutput
init<FilterType:GPUImageOutput where FilterType:GPUImageInput>(filter:FilterType) {
self.filter = filter
}
func setFilter<FilterType:GPUImageOutput where FilterType:GPUImageInput>(filter:FilterType) {
self.filter = filter
}
func someMethod() {
let output = self.filter
let input = self.filter as GPUImageInput
output.someOutputMethod()
input.someInputMethod()
}
}
In Swift 4 you can achieve this with the new & sign (Below an example of a parameter confirming to UIViewController and UITableViewDataSource:
func foo(vc: UIViewController & UITableViewDataSource) {
// access UIViewController property
let view = vc.view
// call UITableViewDataSource method
let sections = vc.numberOfSectionsInTableView?(tableView)
}
In Swift, something like the following should accomplish your task, but it's different than its ObjC counterpart:
typealias GPUImageOutput = UIImage
#objc protocol GPUImageInput {
func lotsOfInput()
}
class GPUImageOutputWithInput: GPUImageOutput, GPUImageInput
{
func lotsOfInput() {
println("lotsOfInput")
}
}
// ...
var someGpuImage = GPUImageOutput()
var specificGpuImage = GPUImageOutputWithInput()
for image in [someGpuImage, specificGpuImage] {
if let specificImage = image as? GPUImageInput {
specificImage.lotsOfInput()
} else {
println("the less specific type")
}
}
UPDATE: now that I understand where/why you have these types ...
GPUImage seems to have a swift example that does what you want, as Swift-ly as possible.
See here:
class FilterOperation<FilterClass: GPUImageOutput where FilterClass: GPUImageInput>: FilterOperationInterface {
...
The type constraint syntax can be applied to functions, too, and with a where clause, that's probably as good as you're going to get directly in Swift.
The more I tried to understand how to port this somewhat common objc trope, the more I realized it was the most Swift-way. Once I saw the example in GPUImage itself, I was convinced it was at least your answer. :-)
UPDATE 2: So, besides the specific GPUImage example I linked to above that uses Swift, the more and more I think about this, either using a where clause to guard the setter function, or using a computable property to filter the set functionality seems the only way to go.
I came up with this strategy:
import Foundation
#objc protocol SpecialProtocol {
func special()
}
class MyClass {}
class MyClassPlus: MyClass, SpecialProtocol {
func special() {
println("I'm special")
}
}
class MyContainer {
private var i: MyClass?
var test: MyClass? {
get {
return self.i
}
set (newValue) {
if newValue is SpecialProtocol {
self.i = newValue
}
}
}
}
var container = MyContainer()
println("should be nil: \(container.test)")
container.test = MyClass()
println("should still be nil: \(container.test)")
container.test = MyClassPlus()
println("should be set: \(container.test)")
(container.test as? MyClassPlus)?.special()
Outputs:
should be nil: nil
should still be nil: nil
should be set: Optional(main.MyClassPlus)
I'm special
(Optionally, you could also use precondition(newValue is SpecialProtocol, "newValue did not conform to SpecialProtocol") in place of the is check, but that will act like an assert() can crash the app if the case isn't met. Depends on your needs.)
#rintaro's answer is a good one, and is a good example of using a where clause as a guard (both nice functional-ly, and Swift-ly). However, I just hate to write a setFoo() function when computable properties exist. Then again, even using a computable property has code smell, since we can't seem to be able to apply a generic type-constraint to the set'er, and have to do the protocol conformance test in-line.
You can use typealias keyword. Here is how to do it:
typealias MyNewType = MyExistingType
It doesn't matter whether MyExistingType is protocol or function or enum. All it needs to be some type. And the best part is you can apply access control on it. You can say
private typealias MyNewType = MyExistingType
That makes MyNewType is only accessible the context that is defined in.

Resources