#StackBounty: #swift #api #asynchronous #ios #controller Update UI once all API calls are done

Bounty: 50

I’m learning Swift at the moment but I would like to produce well-organised code. The goal of my little app is to display the weather of my current location.

I use :

  • the API of Darksky : https://darksky.net/dev for fetching the forecast data
  • the Reverse Geocoding With CLGeocoder for fetching the city’s name of the current coordinate

I would like to improve my main controller and if possible the user experience, let me exmplain:

In the controller, once I have the coordinate (thanks to the class CLLocationManager), I call my two functions for getting the forecast information AND the city’s name.

I have default values in my storyboard that are replaced once I fetched the data. Ideally I would like to update my UI only when I have all data.

import UIKit
import CoreLocation

class ForecastViewController: UIViewController {

    // MARK: IBOulets

    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityNameLabel: UILabel!
    @IBOutlet weak var unitLabel: UILabel!

    // MARK: Properties

    var forecastResponse = ForecastResponse(json: [:]) {
        didSet {
            self.updateTemperatureUI()
        }
    }

    var city: String? {
        didSet {
            self.updateLocaltionUI()
        }
    }

    var coordinate: Coordinate? {
        didSet {
            print("Coordinate has been set")
            self.getCurrentForecast()
            self.getCurrentLocation()
        }
    }

    let secretKey = "123"
    let language = "fr"
    let units = "si"

    var darkskyClient: DarkskyClient!
    let locationManager = LocationManager()
    lazy var geocoder = CLGeocoder()

    override func viewDidLoad() {

        super.viewDidLoad()

        self.darkskyClient = DarkskyClient(secretKey: self.secretKey)

        // Location Service
        self.locationManager.getPermission()
        self.locationManager.didGetLocation = { [weak self] coordinate in
            self?.coordinate = coordinate
        }

        getCurrentLocation()
        getCurrentForecast()

    }

    // MARK: Geocoding Handler

    func processGeocodingResponse(withPlacemarks placemarks: [CLPlacemark]?, error: Error?) {

        if let error = error {
            print("Unable to Reverse Geocode Location ((error))")
        } else {
            if let placemarks = placemarks, let placemark = placemarks.first, let city = placemark.locality {
                self.city = city
            } else {
                self.city = "No Matching City Found"
            }
        }
    }

    // MARK: Private methods

    private func getCurrentForecast() {
        if let coordinate = self.coordinate {
            self.darkskyClient.fetcthCurrentForecast(coordinate: coordinate, lang: self.language, units: self.units, completion: { (result) in
                switch result {
                case .success(let forecastResponse):
                    self.forecastResponse = forecastResponse
                case .failure(let error):
                    print(error)
                }
            })
        }
    }

    private func getCurrentLocation() {
        if let coordinate = self.coordinate {

            // Create Location
            let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)

            // Geocode Location
            geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
                // Process Response
                self.processGeocodingResponse(withPlacemarks: placemarks, error: error)
            }
        }
    }

    private func updateTemperatureUI() {
        if let temperatureInCelsiusDegress = self.forecastResponse?.currently?.temperature,
            let unitName = TemperatureUnitHelper(rawValue: self.units)?.path {
            self.temperatureLabel.text = "(Int(temperatureInCelsiusDegress))"
            self.unitLabel.text = unitName.uppercased()
        }
    }

    private func updateLocaltionUI() {
        self.cityNameLabel.text = self.city
    }
}

What kind of improvements can I do ? and tell me of course what I’ve done wrong in my controller.


Get this bounty!!!

#StackBounty: #ios #swift #uinavigationcontroller #uibarbuttonitem #uinavigationitem Generic Global elegant way to add bar button items…

Bounty: 50

Usually we have a predefined set of UIBarButtonItem in the project that can be used in the project and multiple times like a left menu button to open a side menu, it can be used in different UIViewControllers also a close button that dismiss the presented view controller.

The classic way is to add these buttons as needed, but this introduce a code duplication and we all want to avoid that.

My come up with an approach, but it’s far from being perfect :

enum BarButtonItemType {
    case menu, close, notification
}

enum BarButtonItemPosition{
    case right, left
}

extension UIViewController {

    func add(barButtons:[BarButtonItemType], position: BarButtonItemPosition) {

        let barButtonItems = barButtons.map { rightBarButtonType -> UIBarButtonItem in
            switch rightBarButtonType {
            case .menu:
                return UIBarButtonItem(image: UIImage(named:"menu"),
                    style: .plain,
                    target: self,
                    action: #selector(presentLeftMenu(_:)))
            case .notification:
                return UIBarButtonItem(image: UIImage(named:"notification"),
                style: .plain,
                target: self,
                action: #selector(showNotification(_:)))
            case .close:
                return UIBarButtonItem(image: UIImage(named:"close"),
                    style: .plain,
                    target: self,
                    action: #selector(dismissController(_:)))
            }
        }

        switch position {
        case .right:
            self.navigationItem.rightBarButtonItems = barButtonItems
        case .left:
            self.navigationItem.leftBarButtonItems  = barButtonItems
        }
    }

    // MARK: Actions
    @objc fileprivate func presentLeftMenu(_ sender:AnyObject) {
        self.parent?.presentLeftMenuViewController(sender)
    }

    @objc fileprivate func dismissController(_ sender:AnyObject) {
        self.dismiss(animated: true, completion: nil)
    }

   @objc fileprivate func showNotification(_ sender:AnyObject) {
       let notificationViewController = UINavigationController(rootViewController:NotificationViewController())
       self.present(notificationViewController, animated: true, completion: nil)
   }
}

and then the usage:

override func viewDidLoad() {
    super.viewDidLoad()
    self.add(barButtons: [.close], position: .right)
    self.add(barButtons: [.menu], position: .left)
}

The limitations of my approach are:

  • The extension needs to know how to instantiate new view controller (case of notification for example) and what if viewController must be inited with parameters

  • It assumes that you only want to present a UIViewController

  • Not elegant.

I am sure that there is better way with Swift language and protocol oriented programming that can achieve the intended result with more flexibility, any thoughts ?


Get this bounty!!!

#StackBounty: #html #ios #css #firefox h2 elements all bunched up on top image on iOS & Firefox

Bounty: 100

On the site Codexr.io I am noticing that while the h2 elements work on any size browser for Chrome, however I am seeing with iOS and Firefox, all of the h2s are on top of one another in one of the main images.

Here’s the HTML:

Collaborative

And the CSS:

#top-area .top-area-text, #top-area .region-top-fifth h2, #top-area .region-top-fifth h2 {
    left: 0;
    text-align: center;
    top: 4em;
    width: 100%;
    color: white;
    font-size: 3em;
    text-shadow:
        -1px -1px 0 #000,  
        1px -1px 0 #000,
        -1px 1px 0 #000,
        1px 1px 0 #000;
    text-transform: uppercase;
}

#top-area .top-area-text {
    position: absolute;
}

Is there something I’m missing? Why is Chrome working but Firefox and iOS not? Is something malformed?


Get this bounty!!!

#StackBounty: #ios #swift #sdk #deezer Restoring sessions in Deezer iOS SDK

Bounty: 100

I am using Deezer iOS SDK, in Swift so far everything going well except the session, in Android SDK a method .restoreSession() exists to avoid popup user login every time, but I can’t see it in iOS SDK , so every time session expired use will get popup to login again with hi’s Deezer account, anyway to save or restore session in iOS SDK?

This is the Android restore session code:

// restore any saved session
SessionStore sessionStore = new SessionStore();
if (sessionStore.restore(deezerConnect, context)) {
    // The restored session is valid, navigate to the Home Activity
    Intent intent = new Intent(context, HomeActivity.class);
    startActivity(intent); 
}

is it possible to do this in iOS SDK also?

because when User logged in with Deezer SDK i am not getting notified from the delegate

class DeezerSession : NSObject, DeezerSessionDelegate
{


    var DZRReqManager:DZRRequestManager = DZRRequestManager()
    var deezerConnect:DeezerConnect!

    let defaults = UserDefaults.standard
    var callbackLogin : (()->())? = nil

    //SHARED INSTANCE
    static var instance: DeezerSession!
    class func sharedInstance() -> DeezerSession {
        if self.instance == nil
        {
            self.instance  = DeezerSession();
        }
        return self.instance
    }

    override init()
    {
        super.init()
        self.deezerConnect                  = DeezerConnect(appId: "***" , andDelegate: self )
        self.DZRReqManager.dzrConnect       = self.deezerConnect
        self.deezerConnect.sessionDelegate  = self

        self.retrieveTokenAndExpirationDate()
    }

    // See http://www.deezer.com/fr/developers/simpleapi/permissions
    // for a description of the permissions
    func connectToDeezerWithPermissions()
    {
        print("[DeezerSession] connectToDeezerWithPermissions.")

        //Check if Session still valid update it
        self.deezerConnect.authorize([DeezerConnectPermissionBasicAccess,
                                      DeezerConnectPermissionManageLibrary,
                                      DeezerConnectPermissionOfflineAccess
                                      ])
    }

    func saveToken(token:String,expirationDate:Date,userId:String)
    {
        print("[DeezerSession] Token. (token) : Saved ")
        print("[DeezerSession] Expire Date after. (expirationDate) : Saved ")
        print("[DeezerSession] User ID . (userId) : Saved ")

        defaults.setValue(token, forKey: "DEEZER_TOKEN_KEY")
        defaults.setValue(expirationDate, forKey: "DEEZER_EXPIRATION_DATE_KEY")
        defaults.setValue(userId, forKey: "DEEZER_USER_ID_KEY")
    }

    func deezerSessionDidConnect()
    {


    }

    func retrieveTokenAndExpirationDate()
    {
        self.deezerConnect.accessToken      = defaults.string(forKey: "DEEZER_TOKEN_KEY")
        self.deezerConnect.expirationDate   = defaults.object(forKey: "DEEZER_EXPIRATION_DATE_KEY") as? Date ?? Date()
        self.deezerConnect.userId           = defaults.string(forKey: "DEEZER_USER_ID_KEY")

        print("[DeezerSession] Token. (self.deezerConnect.accessToken) : Restored ")
        print("[DeezerSession] Expire Date. (self.deezerConnect.expirationDate) : Restored ")
        print("[DeezerSession] User ID . (self.deezerConnect.userId) : Restored ")
    }

    func isSessionValid()-> Bool
    {
        print("[DeezerSession] isSessionValid . (self.deezerConnect.isSessionValid()) ")
        return self.deezerConnect.isSessionValid()
    }


    func deezerDidLogin()
    {
        print("[DeezerSession] deezerDidLogin.")
        self.saveToken(token : self.deezerConnect.accessToken,
                       expirationDate : self.deezerConnect.expirationDate  ,
                       userId : self.deezerConnect.userId)

        if  self.callbackLogin != nil
        {
            self.callbackLogin!()
        }
    }

     func deezerDidNotLogin()-> Bool
    {
        print("[DeezerSession] deezerDidNotLogin.")
        return true
    }

     func deezerDidLogout()
    {
        print("[DeezerSession] deezerDidLogout.")
    }

}

all the Delegates is not firing deezerDidLogout deezerDidNotLogin deezerDidLogin


Get this bounty!!!

#StackBounty: #ios #swift #uitableview #rxdatasources Cannot set bind(to: UITableView) with RxSwift Variable asObservable()

Bounty: 100

I’m trying to bind(to:) a collectionView, but the tableView doesn’t work either. I have a viewModel where is my Variable<[]> and I want to subscribe when the value changes, with my tableView.

viewModel.theVariable
        .asObservable()
        .bind(to: tableView.rx.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)){
            (row, item, cell) in
            cell.textLabel?.text = item
        }
        .addDisposableTo(disposeBag)

The XCode tells me Type 'inout UITableView' does not conform to protocol 'ReactiveCompatible' which should be since it’s applicable to any UIView.

I’ve tried Observable with it’s just() and that approach seemed to work correctly. The thing is that I need to have a Variable which I set a value in the viewModel and in the View i need to observe this change. Not sure if Observable serves this method.

The point is that this should work even with Variable? Is it a bug? Im using Swift 3.2


Get this bounty!!!

#StackBounty: #ios #objective-c #google-maps #video #gmsmapview Video is not plying on GMSMarker

Bounty: 50

I am working on play video on GMSMarker pin and below is my code. The display and hide/show pin view, everything work fine. Except video not play. I am using story board with pinview.

@interface MapViewController () <GMSMapViewDelegate>

@property (strong, nonatomic) IBOutlet GMSMapView *mapView;
@property (strong, nonatomic) IBOutlet UIView *pinView;
@property (strong, nonatomic) GMSMarker *london;
@property (strong, nonatomic) AVPlayer *player;
@property (strong, nonatomic) AVPlayerLayer *playerLayer;

@end

@implementation MapViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:51.5 longitude:-0.127 zoom:18];
    self.mapView.camera = camera;
    self.mapView.delegate = self;

    CLLocationCoordinate2D position = CLLocationCoordinate2DMake(51.5, -0.127);
    _london = [GMSMarker markerWithPosition:position];
    _london.title = @"London";
    _london.tracksViewChanges = YES;
    _london.map = self.mapView;

    [self setUpVideoPlayer];
}

- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker {
    [self.player play];
    return self.pinView;
}

-(void)setUpVideoPlayer{

     NSString *videoFilePath = [[NSBundle mainBundle] pathForResource:@"SampleVideo" ofType:@"mp4"];
     AVAsset *avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:videoFilePath]];
     AVPlayerItem *avPlayerItem =[[AVPlayerItem alloc]initWithAsset:avAsset];
     self.player = [[AVPlayer alloc]initWithPlayerItem:avPlayerItem];
     self.playerLayer =[AVPlayerLayer playerLayerWithPlayer:self.player];
     [self.playerLayer setFrame:self.pinView.frame];
     [self.pinView.layer addSublayer:self.playerLayer];
     [self.player seekToTime:kCMTimeZero];
}

enter image description here

enter image description here

Please help me to fix the issue. Why the video is not playing.

Thanks in advance.


Get this bounty!!!

#StackBounty: #ios #avspeechsynthesizer Use AVSpeechSynthesizer in background without stopping f.e. music app

Bounty: 50

I’d like to know how to properly let my iPhone speak one sentence while my app is in background but then return to whatever was playing before.

My question is quite similar to AVSpeechSynthesizer in background mode but again with the difference that I want to be able to “say something” while in background without having to stop Music that is playing. So while my AVSpeechSynthesizer is speaking, music should pause (or be a bit less loud) but then it should resume. Even when my app is currently in background.

What I am trying to archive is a spoken summary of tracking-stats while GPS-Tracking in my fitness app. And chances are that you are listening to music is quite high, and I don’t want to disturb the user…


Get this bounty!!!

#StackBounty: #ios #xcode scrollView Not Scrolling to bottom And content view on scroll view was not Scrolling

Bounty: 500

i Have tools on  Scrollview in viewcontroller as shown in images
i Have tools on  Scrollview in viewcontroller as shown in images

i have developed that scroll view as making view of viewController sige 320 & 840 and i placed scrolview and contents

   _scrollMainView.showsHorizontalScrollIndicator=NO;
 _scrollMainView.delegate=self;
_scrollMainView.indicatorStyle=UIScrollViewIndicatorStyleWhite;
_scrollMainView.contentSize=CGSizeMake(320, 850);


Get this bounty!!!

#StackBounty: #android #ios #react-native #react-native-android #react-native-ios How to schedule background job at specific time in re…

Bounty: 50

I want to execute some Task T at specific time in a day in background in react native. I see that it is possible in android as of now using Headless JS. I found that this library implemented this https://github.com/vikeri/react-native-background-job and allows you to execute stuff in background.

This is not completely what I am looking, it doesn’t allows you to schedule a task T at specific time. Does anyone know any work around for this ?

I have checked this thread Execute code at specific time in react native where I didn’t find a solution of my issue.


Get this bounty!!!

#StackBounty: #ios #swift How do I spawn a pop over view controller programatically?

Bounty: 50

My goal is to show a View Controller programmatically

Current View Controller

enter image description here

and then, if some event gets called or something, (API, or Websocket) I want to call these Views programmatically

enter image description here

But I want to call the last view Controller first and it is supposed to be on top of the first View controller

enter image description here

So technically the last View will have

Transition is Cross Dissolve
Presentation is Over Current Context

How would I do this?


Get this bounty!!!