I've got a UImage, that needs to rotate until my call to the server ends.
But my image rotates only one time and stops after that.
My code:
#IBOutlet var imgLoader: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global(qos: .userInitiated).async {
self.getSalons()
}
self.launchLoaderDesign()
NotificationCenter.default.addObserver(forName:NSNotification.Name("LoadAllShowNotification"), object: nil, queue: nil, using: notificationFinish)
}
func getSalons() -> Void {
let api:ApiSvain = ApiSvain()
api.getHeartStrokeSalon()
api.getSalonForHomePage()
}
func launchLoaderDesign() -> Void {
var posImg:Int = 0
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: { () -> Void in
self.imgLoader.transform = self.imgLoader.transform.rotated(by: CGFloat(M_PI_2))
})
{ (finished) -> Void in
self.launchLoaderDesign()
}
}
func getSalonForHomePage(){
let url = "MY_URL"
Alamofire.request(url, method: .get).validate().responseJSON
{ response in
if (response.error == nil)
{
let json = JSON(response.result.value!)
for (index, element) in json
{
let show:Show = Show(json: element, index: index)
StaticData.arrayOfShow.append(show)
}
NotificationCenter.default.post(name:NSNotification.Name("LoadAllShowNotification"), object: nil, userInfo: nil)
}
else
{
print(response.error!)
}
}
}
My function getSalonForHomePage sends a notification, and when I catch it I use performSegue to move to my new page.
I think my problem came from my misunderstanding of multi-threading.
Ps: I am using alamofire 4, for send request to my server.
Related
I am trying to call model form #main App where the model has the dependency on a repository with init function. The repository has the URLSession and Baseurl properties . I have passed the required property on both approach ..
Here is approach I have tried based on Xcode suggestions ..
#main
struct HomwWorkWithSwiftUIApp: App {
#StateObject var model = FruitsModel(fruitRepository: FruitsRepository.self as! FruitsRepository)
var body: some Scene {
WindowGroup {
ContentView().environmentObject(model)
}
}
}
As a result as was crashed at run time with error Thread 1: signal SIGABRT
The second approach is passing the require parameters like this ..
#main
struct HomwWorkWithSwiftUIApp: App {
#StateObject var model = FruitsModel(fruitRepository: RealFruitsRepository(session: URLSession, baseURL: EndPoint.baseUrl))
var body: some Scene {
WindowGroup {
ContentView().environmentObject(model)
}
}
}
It giving error ..Cannot convert value of type 'URLSession.Type' to expected argument type 'URLSession'
Here is attempt for URLSession instance.
#main
struct HomwWorkWithSwiftUIApp: App {
init() {
}
var url : URLSession
init(url: URLSession) {
self.url = url
}
#StateObject var model = FruitsModel(fruitRepository: RealFruitsRepository(session: url, baseURL: EndPoint.baseUrl))
var body: some Scene {
WindowGroup {
ContentView().environmentObject(model)
}
}
}
Here is the screenshot ..
Here is the repository code ..
import Foundation
protocol FruitsRepository: WebRepository {
func loadFruits() async throws -> [Fruits]
}
struct RealFruitsRepository: FruitsRepository {
let session: URLSession
let baseURL: String
init(session: URLSession, baseURL: String) {
self.session = session
self.baseURL = baseURL
}
func loadFruits() async throws -> [Fruits] {
guard let request = try? API.allFruits.urlRequest(baseURL: baseURL) else {
throw APIError.invalidURL
}
guard let data = try? await call(request: request) else {
throw APIError.unexpectedResponse
}
guard let fruits = getDecodedFruitesResopnse(from: data) else {
throw APIError.unexpectedResponse
}
return fruits
}
private func getDecodedFruitesResopnse(from data: Data)-> [Fruits]? {
guard let fruites = try? JSONDecoder().decode([Fruits].self, from: data) else {
return nil
}
return fruites
}
}
extension RealFruitsRepository {
enum API {
case allFruits
case fruitDetails(Fruits)
}
}
extension RealFruitsRepository.API: APICall {
var path: String {
switch self {
case .allFruits:
return "/all"
case let .fruitDetails(fruit):
let encodedName = fruit.name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
return "/name/\(encodedName ?? fruit.name)"
}
}
var method: String {
switch self {
case .allFruits, .fruitDetails:
return "GET"
}
}
var headers: [String: String]? {
return ["Accept": "application/json"]
}
func body() throws -> Data? {
return nil
}
}
Here is the model class ..
import Foundation
import Combine
protocol FruitsModelInput {
func getFruits() async
}
protocol FruitsModelOutput {
var state: FruitViewStates { get }
var fruitRecordsCount: Int { get }
func getFruit(index: Int)-> Fruits
func getFruitsDetails(for row:Int)-> FruitsDetails
}
struct FruitsDetails {
let genus, name: String
}
final class FruitsModel: ObservableObject {
private var fruitsRepository: FruitsRepository
var fruits: [Fruits] = []
#Published var state: FruitViewStates = .none
private var cancellables:Set<AnyCancellable> = Set()
init(fruitRepository: FruitsRepository) {
self.fruitsRepository = fruitRepository
}
}
extension FruitsModel: FruitsModelOutput {
func getFruitsDetails(for row: Int) -> FruitsDetails {
if row >= 0 {
let fruit = fruits[row]
return FruitsDetails(genus: fruit.genus, name: fruit.name)
}
return FruitsDetails(genus: "", name: "")
}
var fruitRecordsCount: Int {
return fruits.count
}
func getFruit(index: Int) -> Fruits {
if fruits.count > 0 {
return (fruits[index])
} else {
return Fruits(genus: "", name: "", id: 0, family: "", order: "", nutritions: Nutritions(carbohydrates: 0.0, protein: 0.0, fat: 0.0, calories: 0, sugar: 0.0))
}
}
}
extension FruitsModel: FruitsModelInput {
func getFruits() async {
state = .showActivityIndicator
do {
fruits = try await fruitsRepository.loadFruits()
self.state = .showFruitList
} catch let error {
fruits = []
print(error)
state = .showError((error as! APIError).localizedDescription)
}
}
}
I'm pretty new to socket programming and wanted to start with a simple TCP-Client Application. I tested it with several Test-Socket Apps. It always connects and sends the first message successfully, but it doesn't receive any messages. This is my code so far, I hope you can help me with that:
import Foundation
import UIKit
import CocoaAsyncSocket
class setupViewController: UIViewController, GCDAsyncSocketDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
let addr = "192.168.178.43"
let port:UInt16 = 8000
var socket:GCDAsyncSocket!
#IBAction func connectTapped(_ sender: UIButton) {
print("connecting...")
socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
do {
try socket.connect(toHost: addr, onPort: port)
} catch let e {
print(e)
}
}
func socket(_ socket : GCDAsyncSocket, didConnectToHost host:String, port p:UInt16)
{
self.socket.readData(toLength: 1024, withTimeout: -1, tag: 0)
print("Connected to \(addr) on port \(port).")
let data: Data? = "hey its me".data(using: .utf8)
self.socket.write(data!, withTimeout: 2, tag: 0)
}
func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
print(data)
self.socket.readData(toLength: 1024, withTimeout: -1, tag: 0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I know Siri is setup correctly, hence the image below. But the content is not saving in core data. Siri said it created the note, but it's not showing in coredata. This is what I tried so far, any help would be appreciated.
class IntentHandler: INExtension, INCreateNoteIntentHandling {
func handle(intent: INCreateNoteIntent, completion: #escaping (INCreateNoteIntentResponse) -> Void) {
let context = Context.shared.persistentContainer.viewContext
let newNote = Notes(context: context)
newNote.textView = intent.content?.description
// newNote.textView = intent.title?.spokenPhrase
// Save the context
do {
try context.save()
let response = INCreateNoteIntentResponse(code: INCreateNoteIntentResponseCode.success, userActivity: nil)
response.createdNote = INNote(title: intent.title!, contents: [intent.content!], groupName: nil, createdDateComponents: nil, modifiedDateComponents: nil, identifier: nil)
completion(response)
} catch {
completion(INCreateNoteIntentResponse(code: INCreateNoteIntentResponseCode.failure, userActivity: nil))
}
}
func confirm(intent: INCreateNoteIntent, completion: #escaping (INCreateNoteIntentResponse) -> Void) {
completion(INCreateNoteIntentResponse(code: INCreateNoteIntentResponseCode.ready, userActivity: nil))
}
public func resolveContent(for intent: INCreateNoteIntent, with completion: #escaping (INNoteContentResolutionResult) -> Swift.Void) {
let result: INNoteContentResolutionResult
if let content = intent.content {
result = INNoteContentResolutionResult.success(with: content)
} else {
result = INNoteContentResolutionResult.needsValue()
}
completion(result)
}
}
Whenever I tried to save a note
DeleteBackward() deletes only one character, is there any way to keep on deleting backwards ?
I am using emojiKeyboard and I have a delete emoticon. I detect the emoji being the delete emoticon and I call
if emoticon.isDelete{
deleteBackward()
return
}
Update:
Steven's solution works on buttons but not on my UITextView. Will try and find out why. I have tried having the addGestureRecognizer in ViewWillAppear as well as ViewDidLoad.
This should get you started, didn't test but should do the trick.
fileprivate var timer = Timer()
fileprivate var textField = UITextField() //change to your field
override func viewDidLoad() {
super.viewDidLoad()
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
textField.addGestureRecognizer(longPress)
}
func longPress(_ guesture: UILongPressGestureRecognizer) {
if guesture.state == UIGestureRecognizerState.began {
longPressBegun(guesture)
} else if guesture.state == UIGestureRecognizerState.changed {
//longPressStateChanged(guesture)
} else if guesture.state == UIGestureRecognizerState.ended {
longPressEnded()
} else if guesture.state == UIGestureRecognizerState.cancelled {
longPressCancelled()
}
}
func longPressBegun(_ guesture: UILongPressGestureRecognizer) {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(repeatAction), userInfo: nil, repeats: true)
}
func longPressEnded() {
timer.invalidate()
}
func longPressCancelled() {
timer.invalidate()
}
func repeatAction() {
deleteBackward()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
askForPermission()
}
#IBAction func addLocalNotification(_ sender: AnyObject) {
addLocalNotification()
}
func addLocalNotification() {
let content = UNMutableNotificationContent()
content.title = "iOS10.0"
content.body = "Hello Buddy"
content.sound = UNNotificationSound.default()
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "FiveSecond", content: content, trigger: trigger)
// Schedule the notification.
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
print(error)
}
print("should have been added")
}
func askForPermission() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge]) { (granted, error) in
}
}
You have to implement a delegate to UNUserNotificationCenter to tell the system you want to display the notification while the app is running. See the sample here: https://github.com/jerbeers/DemoLocalNotification