The following methods are throwing a warning and not working after converting/migrating to Swift 4.
public func calendar(_ calendar: JTCalendarManager!, prepareDayView dayView: UIView!)
public func calendar(_ calendar: JTCalendarManager!, didTouchDayView dayView: UIView!)
See the images for reference:
In Swift 4, these two methods have different types for the dayView argument ((UIView & JTCalendarDay)! instead of UIView!):
func calendar(_ calendar: JTCalendarManager!, prepareDayView dayView: (UIView & JTCalendarDay)!)
func calendar(_ calendar: JTCalendarManager!, didTouchDayView dayView: (UIView & JTCalendarDay)!)
Related
I am writing some transitioning protocols, and I would like them to only be available to UIView classes:
public protocol TransitioningView where Self: UIView
{
func transitionDelay(pushFrom: UIView?) -> TimeInterval?
func transitionDuration(popTo: UIView?) -> TimeInterval
func transitionDuration(pushFrom: UIView?) -> TimeInterval
func animateTransition(popTo: UIView? , finished: ((Bool) -> Void)?)
func animateTransition(pushFrom: UIView?, finished: ((Bool) -> Void)?)
}
But this doesn't seem quite right. The compiler does not consider a UIView that has been cast to a TransitioningView as being a UIView.
example:
let x = myController.view as? TransitioningView
x.animateTransition(popTo: nil, finished: nil) // OK
x.backgroundColor = .clear // NOPE
This is a bit annoying because sometimes I want to pass around a view that I have confirmed to be a TransitioningView. Is there a better pattern?
In your example, public protocol TransitioningView where Self: UIView, you are defining that the TransitioningView requires an inheritance from UIView, but i can't see any implementation of TransitioningView into UIView.
I'll give you two examples on how you can do this.
First you can create a default implementation of the protocol:
extension TransitioningView {
public func transitionDelay(pushFrom: UIView?) -> TimeInterval? {
return 1
}
public func transitionDuration(popTo: UIView?) -> TimeInterval {
return 1
}
public func transitionDuration(pushFrom: UIView?) -> TimeInterval {
return 1
}
public func animateTransition(popTo: UIView?, finished: ((Bool) -> Void)?) {
}
public func animateTransition(pushFrom: UIView?, finished: ((Bool) -> Void)?) {
}
}
This example will make every object that inherits from UIView conform to TransitioningView, this might be a over-kill depending on how much you utilize the TransitioningView functionality:
extension UIView: TransitioningView {}
The last example will implement TransitioningView directly in the custom class:
class MyCustomView: UIView, TransitioningView {}
class MyCustomLabel: UILabel, TransitioningView {}
Independent of how you implement it they both use the same default implementation in the extension TransitioningView. This behavior can be "overridden" in the either an extension or in the class itself.
extension TransitioningView where Self: UITextField {
public func animateTransition(pushFrom: UIView?, finished: ((Bool) -> Void)?) {
// Some custom transition
}
}
or
class MyCustomView: UIView, TransitioningView {
func transitionDuration(popTo: UIView?) -> TimeInterval {
return 2
}
}
For further reference:
Extensions - The Swift Programming Language (Swift 4)
Protocols - The Swift Programming Language (Swift 4)
I want to make use of a private framework on iOS from a Swift app. I am well aware why this is a bad idea, but it will be useful during testing, so App Store limitations are not an issue, and I have quite exhaustively looked into alternatives.
What I would like to do is something along the lines of this:
dlopen("/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation".fileSystemRepresentation,RTLD_LOCAL);
let eventsclass = NSClassFromString("UIASyntheticEvents") as? UIASyntheticEvents.Type
eventGenerator = eventsclass!.sharedEventGenerator() as! UIASyntheticEvents
The problem is that this will cause a linker error:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_UIASyntheticEvents", referenced from:
type metadata accessor for __ObjC.UIASyntheticEvents in Test.o
If I link the framework directly rather than use dlopen(), it will work fine on the simulator, but will fail to build for an actual device, as the framework supplied in the SDK is for the simulator only and will not link during a device build.
I have tried doing these calls in Objective-C instead, in case it was just the .Type cast that was causing problems, but this does not help. If I access the returned object from Swift, I still get the same error.
I suppose I could create a wrapper in Objective-C that just passes all the calls to the class straight through, but this seems excessive. Is there a more elegant solution to this problem?
I found one solution which requires some manual work, but does work in pure Swift.
The trick is to create an #objc protocol in Swift which matches the Objective-C methods, then do an unsafe cast to that protocol type. In my case, the protocol looks like this:
#objc protocol UIASyntheticEvents {
static func sharedEventGenerator() -> UIASyntheticEvents
//#property(readonly) struct __IOHIDEventSystemClient *ioSystemClient; // #synthesize ioSystemClient=_ioSystemClient;
var voiceOverStyleTouchEventsEnabled: Bool { get set }
var activePointCount: UInt64 { get set }
//#property(nonatomic) CDStruct_3eca2549 *activePoints; // #synthesize activePoints=_activePoints;
var gsScreenScale: Double { get set }
var gsScreenSize: CGSize { get set }
var screenSize: CGSize { get set }
var screen: UIScreen { get set }
var onScreenRect: CGRect { get set }
func sendPinchCloseWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, inRect: CGRect)
func sendPinchOpenWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, inRect: CGRect)
func sendDragWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, withFlick: Bool, inRect: CGRect)
func sendRotate(_: CGPoint, withRadius: Double, rotation: Double, duration: Double, touchCount: UInt64)
func sendMultifingerDragWithPointArray(_: UnsafePointer<CGPoint>, numPoints: Int32, duration: Double, numFingers: Int32)
func sendPinchCloseWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendPinchOpenWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendFlickWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendDragWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendTaps(_: Int, location: CGPoint, withNumberOfTouches: Int, inRect: CGRect)
func sendDoubleFingerTap(_: CGPoint)
func sendDoubleTap(_: CGPoint)
func _sendTap(_: CGPoint, withPressure: Double)
func sendTap(_: CGPoint)
func _setMajorRadiusForAllPoints(_: Double)
func _setPressureForAllPoints(_: Double)
func moveToPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64, duration: Double)
func _moveLastTouchPoint(_: CGPoint)
func liftUp(_: CGPoint)
func liftUp(_: CGPoint, touchCount: UInt64)
func liftUpAtPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64)
func touchDown(_: CGPoint)
func touchDown(_: CGPoint, touchCount: UInt64)
func touchDownAtPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64)
func shake()
func setRinger(_: Bool)
func holdVolumeDown(_: Double)
func clickVolumeDown()
func holdVolumeUp(_: Double)
func clickVolumeUp()
func holdLock(_: Double)
func clickLock()
func lockDevice()
func holdMenu(_: Double)
func clickMenu()
func _sendSimpleEvent(_: Int)
func setOrientation(_: Int32)
func sendAccelerometerX(_: Double, Y: Double, Z: Double, duration: Double)
func sendAccelerometerX(_: Double, Y: Double, Z: Double)
func _updateTouchPoints(_: UnsafePointer<CGPoint>, count: UInt64)
func _sendHIDVendorDefinedEvent(_: UInt32, usage: UInt32, data: UnsafePointer<UInt8>, dataLength: UInt32) -> Bool
func _sendHIDScrollEventX(_: Double, Y: Double, Z: Double) -> Bool
func _sendHIDKeyboardEventPage(_: UInt32, usage: UInt32, duration: Double) -> Bool
//- (_Bool)_sendHIDEvent:(struct __IOHIDEvent *)arg1;
//- (struct __IOHIDEvent *)_UIACreateIOHIDEventType:(unsigned int)arg1; func _isEdgePoint(_: CGPoint) -> Bool
func _normalizePoint(_: CGPoint) -> CGPoint
//- (void)dealloc;
func _initScreenProperties()
//- (id)init;
}
This was converted by hand from a class-dump output. If anyone knows a quicker way to do it, I'd love to know.
Once you have this protocol, you can simply do the following:
dlopen("/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation".fileSystemRepresentation,RTLD_LOCAL)
let eventsclass = unsafeBitCast(NSClassFromString("UIASyntheticEvents"), UIASyntheticEvents.Type.self)
eventGenerator = eventsclass.sharedEventGenerator()
I have a fairly big application which has a lot of collection views. Most of the collection view have same implementations for Data Source and the Flow Layout Delegate (same sizes, margins etc). I am trying to create a single protocol which provides the default implementations of UICollectionViewDataSource and UICollectionViewDelegateFlowLayout. Here is my code.
protocol TiledCollectionView{}
extension UICollectionViewDataSource where Self: TiledCollectionView{
//default implementation of the 3 methods to load the data ...
}
extension UICollectionViewDelegateFlowLayout where Self: TiledCollectionView {
//default implementation for layout methods to set default margins etc...
}
class MyViewController: UIViewController, TiledCollectionView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
// the rest of the required logic for view controller
// here I Don't implement any CollectionView methods since I have provided the default implementation already
}
The problem is that, the compiler complains that MyViewController does not conform to UICollectionViewDataSource. This should not be the case because I am clearly saying that add the default implementations if the type is TiledCollectionView.
Can some one help?
I know it's not exactly what you asked, I tried - it didn't work. Now looking for possible answer, because had similiar situation. But I can offer you such on option how to hide in your custom protocol all the logic for delegate/dataSource implementation.
class CollectionViewProtocolHandler: NSObject, UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 0
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
return UICollectionViewCell() // only for test
}
}
protocol CollectionViewProtocol {
var handler: CollectionViewProtocolHandler! {get set}
mutating func useProtocolForCollectionView(collectionView: UICollectionView)
}
extension CollectionViewProtocol {
mutating func useProtocolForCollectionView(collectionView: UICollectionView) {
handler = CollectionViewProtocolHandler()
collectionView.delegate = handler
collectionView.dataSource = handler
}
}
class ViewController: UIViewController, CollectionViewProtocol {
var handler: CollectionViewProtocolHandler! // CollectionViewProtocol convenience
override func viewDidLoad() {
super.viewDidLoad()
let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: UICollectionViewFlowLayout())
collectionView.backgroundColor = .redColor()
view.addSubview(collectionView)
var reference = self
reference.useProtocolForCollectionView(collectionView) // for initialize protocol
}
}
I expect the problem is that this is an Objective-C protocol. Objective-C has never heard of a protocol extension. Therefore it has no knowledge that this protocol extension is injecting two functions into MyClass. It can't see them, and so as far as it is concerned, the protocol requirements are not satisfied.
To add to, but modify, what katleta3000 answered with, you can restrict a protocol to only apply to a 'class'
CollectionViewProtocol : class
so that you don't need 'useProtocolForCollectionView:' to be mutating
Which then makes it so you don't need that var reference = self and you can just say self.userProtocolForCollectionView(collectionView)
Especially if you only plan on implementing this protocol only with NSObject's or class types (UIViewController, UICollectionView, etc.)
I'd like to expand the functionality of a delegate that I've been using to accept a two different types as the second parameter. When I attempt to add an overloaded method, I get two errors:
So my question is, Is there a way to overload a method in a protocol in swift to allow different parameters?
Error 1
Type 'ViewController' does not conform to protocol 'myCellDelegate'
Error 2
Cannot assign a value of type 'ViewController' to a value of type 'myCellDelegate?'
myCellDelegate.swift
protocol myCellDelegate {
func didChangeState(# sender: SettingCell, isOn: Bool)
func didChangeState(# sender: SettingCell, time: Int) // error
}
(in ViewController.Swift)
class ViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate, myCellDelegate {
cellForRowAtIndexPath
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomSettingCell") as! SettingCell
let section = sectionNames[0]
let logItem = logItems[indexPath.row]
cell.settingsLabel?.text = logItem.settingLabel
cell.settingsSwitch.on = logItem.switchState
cell.cellDelegate = self
return cell
}
Usage
func didChangeState(#sender: SettingCell, isOn: Bool) {
...
}
The immediate answer is YES there is a way to overload a method in a protocol, and I was pretty much there had I only listened to the error messages.
I simply forgot to implement the method in my ViewController. Although its obvious to me now, it wasn't apparent to me at the time because the method name was the same.
So the final code should look like this:
myCellDelegate.swift
protocol myCellDelegate {
func didChangeState(# sender: SettingCell, isOn: Bool)
func didChangeState(# sender: SettingCell, time: Int)
}
ViewController.swift
class ViewController: UITableViewController, UITableViewDelegate, myCellDelegate {
func didChangeState(#sender: SettingCell, isOn: Bool) {
...
}
func didChangeState(#sender: SettingCell, time: Int) {
...
}
}
As #woodstock suggested in the OP, this is probably a good time to use a generic type rather than an overloaded method.
If i have code like:
self.view.addSubview(SomeImage1)
self.view.addSubview(SomeImage2)
self.view.addSubview(SomeImage3)
How do I switch places of view, i understand that the first one would be at index 0 and second at index 1, so is there a way to manually set view index, i am new at managing view and havent found any tutorial good enough to solve my problems.
There's a full set of UIView methods that copes with that:
func bringSubviewToFront(_ view: UIView)
func sendSubviewToBack(_ view: UIView)
func removeFromSuperview()
func insertSubview(_ view: UIView, atIndex index: Int)
func insertSubview(_ view: UIView, aboveSubview siblingSubview: UIView)
func insertSubview(_ view: UIView, belowSubview siblingSubview: UIView)
func exchangeSubviewAtIndex(_ index1: Int, withSubviewAtIndex index2: Int)
...and so on.
You shouldn't be using array indexes to move views.