drawRect / Instagram_Stories

Inspired by Instagram Stories functionality. This source is similar to Instagram Stories, which is having both image and video support.
MIT License
415 stars 76 forks source link

Using Alamofire response as JSON data #85

Closed UtkuDalmaz closed 4 years ago

UtkuDalmaz commented 4 years ago

Hi there

typealias CompletionHandler = ([String:Any]) -> ()
    func getStoriesNF (completion: @escaping CompletionHandler)  {

        let parameters: Parameters = ["user_id": userID]

        Alamofire.request("https://website.com/stories.php", method: .post, parameters: parameters).validate().responseJSON { response in
            switch response.result {
            case .success:
                if let json = response.result.value {
                        completion(json)
                }
            case .failure(_):
                print("hata")
            }
        }
    }

How can I use this response within loadAPIResponse function?

Can you please help me on this?

boominadhaprakash commented 4 years ago

Hi @UtkuDalmaz

Thanks for using this library and we are appreciating your question.

My first question is, the JSON what you are getting is same as our stories.json template?

It's easy for you load the JSON from Alamofire response. Open Modules -> Home -> IGHomeViewModel.swift in our InstagramStories project.

There we will load stories.json using the below code.

private let stories: IGStories? = {
        do {
            return try IGMockLoader.loadMockFile(named: "stories.json", bundle: .main)
        }catch let e as MockLoaderError {
            debugPrint(e.description)
        }catch{
            debugPrint("could not read Mock json file :(")
        }
        return nil
    }()

You can slightly tweak the code like

private let stories: IGStories? = {
        do {
            return try IGMockLoader.loadAPIResponse(response: json)
        }catch let e as MockLoaderError {
            debugPrint(e.description)
        }catch{
            debugPrint("could not read Mock json file :(")
        }
        return nil
    }()

Hope you find the difference between the above two code snippets. IGMockLoader.loadMockFile(named: "stories.json", bundle: .main) => IGMockLoader.loadAPIResponse(response: json)

Regards, Boominadha Prakash

UtkuDalmaz commented 4 years ago

Json is same as your stories.json template

I first get Alamofire response and pass it to self.responseData

func getStoriesNF ()  {
           let parameters: Parameters = ["user_id": userID]

           Alamofire.request("https://server.com/stories.php", method: .post, parameters: parameters).validate().responseJSON { response in
               switch response.result {
               case .success:
                do {
                    let data = try JSONSerialization.data(withJSONObject: response.data!, options: .prettyPrinted)
                self.responseData = data
                } catch {
                  //
                }
              //continue

Then load stories to collectionview

And I use this when story tapped

var data = Data()   //<--- I pass self.responseData here
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if indexPath.row == 0 {
            //
        }else {
            do {
                let stories = try JSONDecoder().decode(IGStories.self, from: data)
                if let stories_copy = try? stories.copy() {
                    let storyPreviewScene = IGStoryPreviewController.init(stories: stories_copy, handPickedStoryIndex:  indexPath.row-1)
                    self.delegate?.goToStories(data: storyPreviewScene)
                } 
            } catch {
            print("error")
            }
        }
    }

I get **Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* +[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write' error when tapped a story

How can I fix it?

UtkuDalmaz commented 4 years ago

I also tried this

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if indexPath.row == 0 {
            //
        }else {
            DispatchQueue.main.async {
                let stories = IGMockLoader.loadAPIResponse(response: data)
                if let stories_copy = try? stories.copy() {
                    let storyPreviewScene = IGStoryPreviewController.init(stories: stories_copy, handPickedStoryIndex:  indexPath.row-1)
                    self.delegate?.goToStories(data: storyPreviewScene)
                }
            }
        }
    }

I get Cannot convert value of type 'Data' to expected argument type '[String : Any]'

UtkuDalmaz commented 4 years ago

Here is the JSON from the service, maybe it is incorrect ?

[{
    "stories": [{
        "id": "s1",
        "last_updated": "1582627402",
        "user": {
            "id": "2",
            "name": "yunuskasarci",
            "picture": "https:\/\/server.com\/ios\/images\/profile_pic\/116534.jpg"
        },
        "snaps_count": 1,
        "snaps": [{
            "id": "c1",
            "mime_type": "image",
            "url": "chttps:\/\/server.com\/ios\/stories\/image\/3434.jpg",
            "last_updated": "c1582627402"
        }]
    }],
    "count": 1
}]
ranmyfriend commented 4 years ago

Hi @UtkuDalmaz There is a mistake in your JSON. currently, we kept last_updated as Integer. NOT A STRING. Rest of the things are cool. Let me know if you need any help.

UtkuDalmaz commented 4 years ago

Yeah I just realized it and corrected but I still have problem

Let me explain

Alamofire.request("https://server.com/ios/stories.php", method: .post, parameters: parameters).validate().responseString { response in
               switch response.result {
               case .success:

                let data = response.result.value!.data(using: .utf8)!
                self.responseData = data

I get responseString (json) and convert it to Data and assing to self.responseData

Then check this part

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if indexPath.row == 0 {
            //
        } else {
            DispatchQueue.main.async {

                do {
                    let stories = try JSONDecoder().decode(IGStories.self, from: self.responseData)
                    if  let stories_copy = try? stories.copy() {
                        let storyPreviewScene = IGStoryPreviewController.init(stories: stories_copy, handPickedStoryIndex:  indexPath.row-1)
                        self.delegate?.goToStories(data: storyPreviewScene)
                    }
                } catch {
                    print("hata")
                }
            }
        }
    }

Here the problem let stories = try JSONDecoder().decode(IGStories.self, from: self.responseData) This line doesn't work and I don't know why

Have an Idea?

ranmyfriend commented 4 years ago

@UtkuDalmaz Dont worry. can you please paste me the entire response here. let me apply it from my end and will solve it as soon as possible

UtkuDalmaz commented 4 years ago

[{"stories":[{"id":"s1","last_updated":1582627402,"user":{"id":"2","name":"yunuskasarci","picture":"https:\/\/jemiyet.com\/ios\/images\/profile_pic\/116534.jpg"},"snaps_count":1,"snaps":[{"id":"c1","mime_type":"image","url":"https:\/\/jemiyet.com\/ios\/stories\/image\/3434.jpg","last_updated":"1582627402"}]}],"count":1}]

ranmyfriend commented 4 years ago

Please wait. I will check and update you soon.

UtkuDalmaz commented 4 years ago

I was able to run it now finally (I removed the [ and ] brackets from json). Story view controller appeared but this time I get these

IGStoryPreviewHeaderView.swift I got 2 errors

Line 59 button.setImage(#imageLiteral(resourceName: "ic_close"), for: .normal) Error: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

Line 229 pv.widthConstraint! Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Screen Shot 2020-02-25 at 19 30 30
ranmyfriend commented 4 years ago

I got your problem. @UtkuDalmaz

Your response is an Array of a dictionary. But we kept simple dictionary. So instead of passing [[:]] like this. you can simply pass [:] Dictionary It will work. or else, you pass the first object of your received array. That's it. it will work.

Let me know if you need anything else

UtkuDalmaz commented 4 years ago

I also have this problem

IGSnapProgressView.swift

Screen Shot 2020-02-25 at 19 47 12
ranmyfriend commented 4 years ago

Hi @UtkuDalmaz

1)ic_close image we have added in Assets.xcassets could you please confirm this once you from your end? 2)pv.widthConstraint error. can you please let us know use case?

ranmyfriend commented 4 years ago

@UtkuDalmaz I guess WidthConstraint is getting disturbance with Apple new property width_constraint. Let me check and update you soon. can you please tell me which Xcode version you are using?

UtkuDalmaz commented 4 years ago

1- Fixed Thanks 2- What do you mean?

I use 11.3.1 xcode

ranmyfriend commented 4 years ago

Are you using Swift 5 Can you please confirm? @UtkuDalmaz

UtkuDalmaz commented 4 years ago

Yes Swift 5

ranmyfriend commented 4 years ago

for me, it's working fine. I dont know why it's not working for you. Even am also using Swift 5 and same Xcode version. it's building nicely here.

UtkuDalmaz commented 4 years ago

What may cause it? It works good in your sample project but it gives error in my project Can I just change public var widthConstraint: NSLayoutConstraint? variable name to sth different?

UtkuDalmaz commented 4 years ago

I now realized that it confuses with 2 variable names of 2 pod libraries

ranmyfriend commented 4 years ago

Oh is it. Do whatever changes you want. We want you to feel free to use this library :)

UtkuDalmaz commented 4 years ago

Thanks I fixed everything now.