Pages

Monday, August 10, 2020

Some swift tips

 In this post, I am going to quote some important notes to help everyone new to swift like me

  • “Constants and variables created with optional binding in an if statement are available only within the body of the if statement. In contrast, the constants and variables created with a guard statement are available in the lines of code that follow the guard statement, as described in Early Exit.”
  • var: String! 
    • Implicitly Unwrapped Optionals

  • optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist.  Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time. These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation point (String!) rather than a question mark (String?) after the type that you want to make optional. Rather than placing an exclamation point after the optional’s name when you use it, you place an exclamation point after the optional’s type when you declare it. Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter.  
  • “An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a non-optional value, without the need to unwrap the optional value each time it’s accessed. The following example shows the difference in behavior between an optional string and an implicitly unwrapped optional string when accessing their wrapped value as an explicit String:” 
  • “Don’t use an implicitly unwrapped optional when there’s a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable.”
  •  

     

    What is the difference between nil of Swift and nil of Objective-C?

     Swift's nil isn't the same as nil in Objective-C. In Objective-C, nil is a pointer to a nonexistent object.

    In Swift, nil is not a pointer, it's the absence of a value of a certain type. 

    Optionals of any type can be set to nil, not just object types.


    “The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structures, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there’s a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants.”


    Excerpt From: Apple Inc. “The Swift Programming Language (Swift 5.2)”. Apple Books. https://books.apple.com/us/book/the-swift-programming-language-swift-5-2/id881256329

    Saturday, July 18, 2020

    A simple Example of SignalProducer ReactiveSwift

    Recently I started to work on a project which is totally in Swift and Signal. As I mostly worked on Objective-C and C++ based projects, from Objective C background I really don’t like Swift that much, and honestly this ReactiveSwift, I hope it will change after some time. And for me, SignalProducer or Signals is very complex. When I searched for tutorials with real-life examples, what I found is that, whether they are too old or does not meet my requirements, also I didn’t get much time to study these things. 

    If you want to learn theory or want to clear your concept about ReactiveSwift or Signals this article is not for you. Here I will share the examples I came up with to help me to implement the same scenario in my project. 

    If you are already experienced in these please feel free to share your comments so that I and other people get to learn something from you :)


    Let’s get to point

    Let's say we have a Downloader class which only perform the download, and which have no idea about ReactiveSwift, we want to integrate this class with our app using ReactiveSwift, also we have DownloaderDelegate. Let's check them first.

    protocol DownloaderDelegate {
    func downloadFinished()
    func downloadCanceled()
    }
    class Downloader {
    var progress: Int
    var shouldStop: Bool
    var delegate: DownloaderDelegate?
    init(delegate: DownloaderDelegate) {
    progress = 0
    shouldStop = false
    self.delegate = delegate
    }
    func startDownloading() {
    DispatchQueue.global().async {
    //lets say we are donwloading here,
    for index in 0..<10 {
    sleep(1)
    log("[Downloader] Progress \(index*10)%")
    if self.shouldStop {
    self.delegate?.downloadCanceled()
    return
    }
    }
    self.delegate?.downloadFinished()
    }
    }
    func stopDownloading() {
    shouldStop = true
    }
    }

    Now Let's say we are going to create a DownloadManager class which will use this class and implement SignalProducer so that our application can access this just like other classes using ReactiveSwift.

    class DownloadManager {
    var observer: Signal<Int, Error>.Observer? = nil
    var lifetime: Lifetime? = nil
    var downloader: Downloader?
    func start() -> SignalProducer<Int, Swift.Error> {
    let signalProducer: SignalProducer<Int, Swift.Error> = SignalProducer { (observer, lifetime) in
    //this block won't execute untill someone start this signal
    log("[DownloadManager] Download Starting")
    self.downloader = Downloader(delegate: self)
    self.downloader?.startDownloading()
    self.observer = observer
    self.lifetime = lifetime
    }
    return signalProducer
    }
    func stop() {
    log("[DownloadManager] IN")
    self.downloader?.stopDownloading()
    log("[DownloadManager] OUT")
    }
    }


    Here is the Tester class where we will use DownloadManager class

    class DownloadTester {
    func testDownloader() {
    let manager = DownloadManager()

    manager.start().startWithResult { (result) in
    switch result {
    case .success(let progress) :
    print(progress)
    print("[DownloadTester] Download Complete: \(progress)")
    case .failure(let err):
    print(err)
    }
    }
    //to test stop downloading
    DispatchQueue.global().async {
    sleep(3)
    manager.stop()
    }
    }
    }


    If you want to see the whole class please check here

    I wanted to use github gist but no way I could embedded it here :( 

    If you know how to do that please share.

    https://github.com/razibdeb/ReactiveSwiftSamples/blob/master/DownloaderSample.swift

    Thursday, July 16, 2020

    Simple BSD Socket Client Server Example for macOS iOS

    Today I am going to share about a simple Client Server example I have been working on to clear my concepts of BSD Socket. You can work on high leven APIs like CFSocket, But sometimes you need the help of a pure socket. 

    I tested this code in macOS

    RCDBSDServer.h

    //

    //  RCDServer.h

    //  HelloMacObj

    //

    //  Created by Razib Chandra Deb on 15/7/20.

    //  Copyright © 2020 Razib Chandra Deb. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    NS_ASSUME_NONNULL_BEGIN


    @interface RCDBSDServer : NSObject

    -(BOOL) startOnPort:(int) port;

    -(void) stop;

    -(void) sendString: (NSString *) string;

    -(void) readData:(int) length;

    @end


    NS_ASSUME_NONNULL_END



    RCDBSDServer.mm


    //

    //  RCDServer.m

    //  HelloMacObj

    //

    //  Created by Razib Chandra Deb on 15/7/20.

    //  Copyright © 2020 Razib Chandra Deb. All rights reserved.

    //


    #import "RCDBSDServer.h"

    #include <netdb.h>

    #include <netinet/in.h>

    #include <sys/ioctl.h>

    #include <sys/un.h>

    #include <err.h>

    #include <fcntl.h>

    #include <arpa/inet.h>

    #import <objc/runtime.h>

    /*

     

     https://www.tutorialspoint.com/unix_sockets/socket_server_example.htm

    Create a socket with the socket() system call.


    Bind the socket to an address using the bind() system call. For a server socket on the Internet, an address consists of a port number on the host machine.


    Listen for connections with the listen() system call.


    Accept a connection with the accept() system call. This call typically blocks until a client connects with the server.


    Send and receive data using the read() and write() system calls.

    */

    @implementation RCDBSDServer {

        int sockfd, portno, n, newSockFd;

        struct sockaddr serv_addr;

        struct hostent *server;

        

        struct sockaddr_in client_addr;

        socklen_t client_addr_len;

    }



    -(id) init {

        self = [super init];

        if ( self != nil) {

            

        }

        return self;

    }


    -(BOOL) startOnPort:(int) port {

        // Connect socket

        struct sockaddr_in addr;

        bzero((char *)&addr, sizeof(addr));

        

        addr.sin_family = AF_INET;

        addr.sin_port = htons(port);

        //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

        addr.sin_addr.s_addr = htonl(INADDR_ANY);

        //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

        

        socklen_t socklen = sizeof(addr);

        

        

        /* First call to socket() function */

        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        

        if (sockfd < 0) {

            Log(@"[Server] socket creation failed");

            return NO;

        }

        

    //    int on = 1;

    //    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {

    //        close(sockfd);

    //        Log(@"Error on setsockopt");

    //        return false;

    //    }

    //

    //    if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {

    //        close(sockfd);

    //        Log(@"Error on fcntl");

    //        return false;

    //    }


        if (bind(sockfd, (struct sockaddr*)&addr, socklen) != 0) {

            close(sockfd);

            Log(@"Error on bind");

            return false;

        }

        

        /* Now start listening for the clients, here process will

           * go in sleep mode and will wait for the incoming connection

        */

        if (listen(sockfd, DATA_CHUNK) != 0) {

            close(sockfd);

            Log(@"Error on listen");

            return false;

        }

        else {

            Log(@"listen success");

        }

        

        client_addr_len = sizeof(client_addr);

        /* Accept actual connection from the client */

        newSockFd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);

         

        if (newSockFd < 0) {

           Log(@"ERROR on accept");

            return false;

        }

        

        /* If connection is established then start communicating */

      

        return true;

    }

    -(void) stop {

        close(sockfd);

    }

    -(void) sendString: (NSString *) string {

         const char * buffer = [string cStringUsingEncoding:NSUTF8StringEncoding];

         ssize_t n = write(newSockFd, buffer, (int) strlen(buffer));

         Log(@"[Server] Data sent %zd", n);

    }

    -(void) readData:(int) length {

        char data[DATA_CHUNK];

        

        memset(data, 0, DATA_CHUNK);

        ssize_t n = read(newSockFd, data, length);

        Log(@"[Server] Data read %zd Data \n%s\n", n, data);

    }

    @end




    RCDBSDClient.h

    //

    //  RCDBSDClient.h

    //  HelloMacObj

    //

    //  Created by Razib Chandra Deb on 15/7/20.

    //  Copyright © 2020 Razib Chandra Deb. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    NS_ASSUME_NONNULL_BEGIN


    @interface RCDBSDClient : NSObject

    -(BOOL) connectToServerIp:(NSString *) ipAddres withPort:(int) port;

    -(void) stop;

    -(void) sendString: (NSString *) string;

    -(void) readData:(int) length;

    @end


    NS_ASSUME_NONNULL_END



    RCDBSDClient.mm

    //

    //  RCDBSDClient.m

    //  HelloMacObj

    //

    //  Created by Razib Chandra Deb on 15/7/20.

    //  Copyright © 2020 Razib Chandra Deb. All rights reserved.

    //


    #import "RCDBSDClient.h"

    #include <netdb.h>

    #include <netinet/in.h>

    #include <sys/ioctl.h>

    #include <sys/un.h>

    #include <err.h>

    #include <fcntl.h>

    #include <arpa/inet.h>


    /*

     https://www.tutorialspoint.com/unix_sockets/socket_client_example.htm

     Create a socket with the socket() system call.


     Connect the socket to the address of the server using the connect() system call.


     Send and receive data. There are a number of ways to do this, but the simplest way is to use the read() and write() system calls.

     */


    @implementation RCDBSDClient {

        int sockfd, portno, n;

        struct sockaddr serv_addr;

        struct hostent *client;

    }


    -(id) init {

        self = [super init];

        if ( self != nil) {

            

        }

        return self;

    }



    -(BOOL) connectToServerIp:(NSString *) ipAddres withPort:(int) port {

        

        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        if (sockfd == -1) {

            Log(@"Error on socket");

            return NO;

        }

        

        // prevent SIGPIPE

        int on = 1;

        setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));

        

        struct hostent *serverAddres = gethostbyname([ipAddres cStringUsingEncoding:NSUTF8StringEncoding]);

        

        // Connect socket

        struct sockaddr_in addr;


        

        bzero((char *) &addr, sizeof(addr));

        addr.sin_family = AF_INET;

        bcopy((char *)serverAddres->h_addr, (char *)&addr.sin_addr.s_addr, serverAddres->h_length);

        addr.sin_port = htons(port);

        

        socklen_t socklen = sizeof(addr);

        if (connect(sockfd, (struct sockaddr*)&addr, socklen) == -1) {

            Log(@"Error on connect");

            return NO;

        }

        

        Log(@"Connection Success");

        

        return true;

    }

    -(void) stop {

        close(sockfd);

    }

    -(void) sendString: (NSString *) string {

        const char * buffer = [string cStringUsingEncoding:NSUTF8StringEncoding];

        ssize_t n = write(sockfd, buffer, (int) strlen(buffer));

        Log(@"[Client] Data sent %zd", n);

    }

    -(void) readData:(int) length {

        char data[DATA_CHUNK];

        memset(data, 0, DATA_CHUNK);

        ssize_t n = read(sockfd, data, length);

        Log(@"[Client] Data read %zd Data \n%s\n", n, data);

    }

    @end




    Please feel free to share your thoughts.