martes, 27 de diciembre de 2016

iOS: Table view text field picker

// DownTableViewCell
import UIKit

class DownTableViewCell: UITableViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
       
        setup()
    }
   
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
       
        setup()
    }
   
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
       
        setup()
    }
       
    private func setup() {
       
        textLabel?.highlightedTextColor = UIButton().tintColor
        backgroundColor = UIColor(red: 208/255.0, green: 213/255.0, blue: 219/255.0, alpha: 1)
        selectedBackgroundView = createBackgroundView()
    }
   
    private func createBackgroundView() -> UIView {
       
        let backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height - 1))
        backgroundView.backgroundColor = UIColor(red: 208/255.0, green: 213/255.0, blue: 219/255.0, alpha: 1)
       
        return backgroundView
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        accessoryType = selected ? .checkmark : .none
    }
}

// DownTableView
import UIKit

class DownTableView: UIControl, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
    
    var textField: UITextField!
    var shouldDisplayCancelButton: Bool = true
    var data: [ProductAttribute] = [ProductAttribute]()
    var selectedValuesString: String = ""
    var selectedValues: [ProductAttribute] = [ProductAttribute]()
    var previousSelectedValues: [ProductAttribute] = [ProductAttribute]()
    var tableView: UITableView?

    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */
    
    init(textField: UITextField, withData data: [ProductAttribute]) {
        
        super.init(frame: CGRect.zero)
        
        self.textField = textField
        self.textField.delegate = self
        self.textField.placeholder = "Tap to choose..."
        self.textField.rightView = UIImageView(image: UIImage(named: "downArrow"))
        self.textField.rightView?.contentMode = UIViewContentMode.scaleAspectFit
        self.textField.rightView?.clipsToBounds = true
        self.textField.rightViewMode = UITextFieldViewMode.always
        
        self.data = data
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func showArrowImage(_ show:Bool) {
        self.textField.rightViewMode = show ? UITextFieldViewMode.always : UITextFieldViewMode.never
    }
    
    func doneClick(sender: Any?) {
        
        addAllSelectedValueToPrevious()
        
        textField.resignFirstResponder()
        
        if self.textField.text?.length == 0 {
            self.setValue(atIndex:-1)
            self.textField.placeholder = "Tap to choose..."
        }
        
        sendActions(for: UIControlEvents.valueChanged)
    }
    
    private func addAllSelectedValueToPrevious() {
        
        previousSelectedValues.removeAll()
        
        for value in selectedValues {
            previousSelectedValues.append(value)
        }
    }
    
    func cancelClicked(sender: Any?) {
        
        textField.resignFirstResponder()
        
        if previousSelectedValues.count == 0 {
            textField.placeholder = "Tap to choose..."
        }
        
        textField.text = toString(productsAttributes: previousSelectedValues)
    }
    
    func setValue(atIndex index:NSInteger) {
        
        if let tableView = self.tableView, index >= 0 {
            self.tableView(tableView, didSelectRowAt: IndexPath(item: index, section: 0))
        }
    }
    
    func showTableView(sender: Any?) {
        
        tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 320, height: 216))
        tableView?.allowsMultipleSelection = true
        tableView?.dataSource = self
        tableView?.delegate = self
        tableView?.cellLayoutMarginsFollowReadableWidth = false
        
        for value in previousSelectedValues {
            tableView?.selectRow(at: IndexPath(row: data.index(of: value)!, section: 0), animated: false, scrollPosition: .none)
        }
        
        if textField.text?.length == 0 {
//            setSelected(index:0)
        }
        
        let toolbar = UIToolbar()
        toolbar.barStyle = UIBarStyle.default
        toolbar.sizeToFit()
        
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(DownTableView.doneClick(sender:)))
        
        if shouldDisplayCancelButton {
            
            let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(DownTableView.cancelClicked(sender:)))
            
            toolbar.setItems([cancelButton, flexibleSpace, doneButton], animated: false)
            
        } else {
            toolbar.setItems([flexibleSpace, doneButton], animated: false)
        }
        
        textField.inputView = tableView
        textField.inputAccessoryView = toolbar
    }
    
    // UITextFieldDelegate
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        return true
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField) {
        if data.count > 0 {
            showTableView(sender: textField)
        }
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        textField.isUserInteractionEnabled = true
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        return false
    }
    
    // UITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
        
        if cell == nil {
            cell = DownTableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")
        }
        
        let item = data[indexPath.row]
        
        cell?.textLabel?.text = item.name
        
        return cell!
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 44
    }
    
    // UITableViewDelegate
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        selectedValues.append(data[indexPath.row])
        
        textField.text = toString(productsAttributes: selectedValues)
    }
    
    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        
        let element = data[indexPath.row]
        
        if let index = selectedValues.index(of: element) {
            selectedValues.remove(at: index)
        }
        
        textField.text = toString(productsAttributes: selectedValues)
    }
    
    private func toString(productsAttributes list:[ProductAttribute]) -> String {
        
        var selectedValuesStrings = [String]()
        
        for value in selectedValues {
            selectedValuesStrings.append(value.name!)
        }
        
        return selectedValuesStrings.joined(separator: ",")
    }
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        
        if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
            cell.separatorInset = UIEdgeInsets.zero
        }
        if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) {
            cell.preservesSuperviewLayoutMargins = false
        }
        if cell.responds(to: #selector(setter: UIView.layoutMargins)) {
            cell.layoutMargins = UIEdgeInsets.zero
        }
    }
}

lunes, 26 de diciembre de 2016

iOS: Upload to AppStore

1) Organizer

2) Application Loader

Choose Xcode > Open Developer Tool > Application Loader from the menu bar.

You need to generate the ipa for App Store distribution.

jueves, 24 de noviembre de 2016

iOS: Date picker for text field

Example with two text fields:

let fromDate = UITextField()
let toDate = UITextField()
let datePicker = UIDatePicker()
let dateFormatter = DateFormatter()

...

dateFormatter.dateFormat = "MM-dd-yyyy"
datePicker.datePickerMode = UIDatePicker.Mode.date
datePicker.addTarget(self, action: #selector(<YouViewController>.datePickerValueChanged(sender:)), for: UIControl.Event.valueChanged)

...

let date = Date()
fromDate.text = dateFormatter.string(from: date)
fromDate.textAlignment = NSTextAlignment.left
fromDate.inputView = datePicker
fromDate.delegate = self

let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 44))
        let doneBtn = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(dateSelected))
        let cancelBtn = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(dismissPicker))
        toolbar.setItems([cancelBtn, doneBtn], animated: false)
        fromDate.inputAccessoryView = toolbar

toDate.text = dateFormatter.string(from: date)
toDate.textAlignment = NSTextAlignment.left
toDate.inputView = datePicker
toDate.delegate = self

...

@objc func datePickerValueChanged(sender: AnyObject) {
        if (fromDate.isFirstResponder) {
            fromDate.text = dateFormatter.string(from: datePicker.date)
         
        } else {
            toDate.text = dateFormatter.string(from: datePicker.date)
        }
    }

// UITextFieldDelegate
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return false
}

martes, 1 de noviembre de 2016

iOS: TableView row height given by image in ImageView

Objective C
[[Server sharedInstance] getItems:^(id response, NSError *error) {
        
        [self hideActivityIndicator];
        
        if (error) {
            [self showErrorDialogWithMessage:error.localizedDescription];
            
        } else {
            self.items = ((NSArray<Item*>*)response).data;
            self.itemsHeights = [[NSMutableArray alloc] initWithCapacity:self.items.count];
            
            for (int i = 0; i < self.items.count; i++) {
                [self.itemsHeights addObject:[NSNumber numberWithInt:160]];
            }
            
            if (self.items.count != 0) {
                [self noResultsViewHidden:YES];
            }
            
            [self.tableView reloadData];
        }
    }];
        
#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.items.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Product* item = item = self.items[indexPath.row];
      
    MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    // Customize cell
        
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:item.picture]];
    [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
    
    __block UIImageView* imageViewRef = cell.itemImageView;
    __block NSIndexPath *blockIndexPath = indexPath;
    
    [cell.itemImageView cancelImageDownloadTask];
    
    AFImageDownloader* downloader = [UIImageView sharedImageDownloader];
    UIImage *cachedImage = [downloader.imageCache imageforRequest:request withAdditionalIdentifier:nil];
        
    if (cachedImage) {
        cell.productImageView.image = cachedImage;
        
        long height = cell.frame.size.width * cachedImage.size.height / cachedImage.size.width;
        [self.itemsHeights setObject:[NSNumber numberWithLong:height] atIndexedSubscript:blockIndexPath.row];
    
    } else {
        [cell.productImageView setImageWithURLRequest:request placeholderImage:nil success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull image) {
            
            long height = cell.frame.size.width * image.size.height / image.size.width;
            [self.itemsHeights setObject:[NSNumber numberWithLong:height] atIndexedSubscript:blockIndexPath.row];
            
            float scale = image.size.width / self.tableView.frame.size.width;
            
            UIImage* scaledImage = [UIImage imageWithCGImage:image.CGImage scale:image.scale * scale orientation:image.imageOrientation];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                imageViewRef.image = scaledImage;
                
                if ([self.tableView.indexPathsForVisibleRows containsObject:blockIndexPath]) {
                    [self.tableView beginUpdates];
                    [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    [self.tableView endUpdates];
                }
            });
            
        } failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
            imageViewRef.image = nil;
        }];
    }
    
    
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    return self.itemsHeights[indexPath.row].longValue;
}

lunes, 31 de octubre de 2016

iOS: Objective C code in Swift

1) Create a header file: ProjectName-Bridging-Header.h
2) Physically it place it inside your project’s folder (not in the root)
3) In Xcode it should appear inside your project’s folder
4) In “Build Settings”:
a) Place the path to your header in “Objective-C Bridging Header”. For example: “ProjectFolder/ProjectName-Bridging-Header.h”
b) Make sure “Install Objective-C Compatibility Header” is set to “Yes”
c) Under “Linking”, “Other Linker Flags” should include “-ObjC”

6) Inside your bridging header import all your necessary headers.

martes, 18 de octubre de 2016

Android: setSelection spinner without triggering onItemSelected

spinner.setSelection(position, false);

Also you need to place "spinner.setOnItemSelectedListener(...)" AFTER "spinner.setAdapter(...)"

martes, 11 de octubre de 2016

iOS: Swift code in objective C project

1) Create new *.swift file (in Xcode) or add it by using Finder
2) Add swift bridging empty header if Xcode have not done this before (see 4 below)
3) Implement your Swift class by using @objc attribute:
import UIKit

@objc class Hello: NSObject {
    func sayHello() {
        print("Hi there!")
    }
}
4) Open Build Settings and check those parameters:
    Product Module Name : myproject
    Defines Module : YES
    Embedded Content Contains Swift : YES
    Install Objective-C Compatibility Header : YES
    Objective-C Bridging Header : $(SRCROOT)/Sources/SwiftBridging.h
5) Import header (which is auto generated by Xcode) in your *.m file
    #import "myproject-Swift.h"
6) Clean and rebuild your Xcode project
7) Profit!

miércoles, 5 de octubre de 2016

iOS: UITextView text content doesn't start from the top

Swift

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        reachOutTextView.setContentOffset(CGPointMake(0, -14), animated: false)

    }

martes, 4 de octubre de 2016

iOS: Round image view

Swift
     
        imageView.layer.cornerRadiusimageView.frame.height/2
        imageView.clipsToBounds = true

Objective C

self.imageView.layer.cornerRadius = self. imageView.frame.size.width/2;
self. imageView.layer.borderColor = [UIColor whiteColor].CGColor;
self. imageView.layer.borderWidth = 2;

self. imageView.layer.masksToBounds = YES;

Interface Builder



Note: 

1) If you are using constraints make sure that the constraint height is the same as the image view size in the interface builder
2) You can't set border color in IB


iOS: Present view controller modally over current context

Swift

let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let vc: UIViewController = storyboard.instantiateViewController(withIdentifier: "AddPaymentViewController")
            vc.modalPresentationStyle = UIModalPresentationStyle.overFullScreen;
            vc.modalTransitionStyle = UIModalTransitionStyle.coverVertical;
           
           
            self.present(vc, animated: true, completion: nil)

lunes, 3 de octubre de 2016

iOS: Screen scale / Scaling

Swift

let px = 1 / UIScreen.mainScreen().scale

Objective C


let px = 1 / [UIScreen mainScreen].scale

viernes, 30 de septiembre de 2016

iOS: Remove left gap from row separator

Objective C

#pragma mark - UITableViewDelegate method

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Remove seperator inset
    if ([cell respondsToSelector : @selector (setSeparatorInset :)]) {
        [cell setSeparatorInset : UIEdgeInsetsZero ];
    }
    
    // Prevent the cell from inheriting the Table View's margin settings
    if ([cell respondsToSelector : @selector (setPreservesSuperviewLayoutMargins :)]) {
        [cell setPreservesSuperviewLayoutMargins : NO ];
    }
    
    // Set Your explictly cell's layout margins
    if ([cell respondsToSelector : @selector (setLayoutMargins :)]) {
        [cell setLayoutMargins : UIEdgeInsetsZero ];
    }

}

Swift

// In viewDidLoad
tableView?.cellLayoutMarginsFollowReadableWidth = false

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
            cell.separatorInset = UIEdgeInsets.zero
        }
        if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) {
            cell.preservesSuperviewLayoutMargins = false
        }
        if cell.responds(to: #selector(setter: UIView.layoutMargins)) {
            cell.layoutMargins = UIEdgeInsets.zero
        }
    }

jueves, 29 de septiembre de 2016

iOS: Navigation bar with custom font

Swift

self.navigationBar.titleTextAttributes = [ NSFontAttributeName: UIFont(name: "Questrial-Regular", size: 15)!, NSForegroundColorAttributeName: UIColor.whiteColor()]

iOS: Transparent navigation bar

Swift
        self.navigationBar.shadowImage = UIImage()
        self.navigationBar.isTranslucent = true
        self.navigationBar.setBackground(UIImage(), forBarMetrics: .default)

iOS: Setup navigation bar

Swift

On .plist:
View controller-based status bar appearance -> YES

private func _setupNavigationBar() -> Void {
        
        self.navigationBar.shadowImage = nil;
        self.navigationBar.translucent = false;
        self.navigationBar.barTintColor = UIColor.clearColor() // Bar background color
        self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()] // Title text color
        self.navigationBar.setBackgroundImage(nil, forBarMetrics: .Default) // No background image with background clear color makes the bar transparent

    }

override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

Note: 

1) If on a presented view controller:

On presenter view controller:
override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.presentedViewController
    }
    
    override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.presentedViewController

    }

On presented view controller:


override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    
    override var prefersStatusBarHidden: Bool {
        return false

    }

2) CARE Status bar's background color will be the views background color

iOS: Generate amazon signature

NSMutableArray* array = @[ [NSString stringWithFormat:@"AWSAccessKeyId=%@", self.credentials[@"AWSAccessKeyId"]],
                                   [NSString stringWithFormat:@"AssociateTag=%@", self.credentials[@"AssociateTag"]],
                                   @"Availability=Available",
                                   [NSString stringWithFormat:@"Keywords=%@", [string urlencode]],
                                   @"Operation=ItemSearch",
                                   @"ResponseGroup=Medium",
                                   // [NSString stringWithFormat:@"SearchIndex=%@", category],
                                   @"SearchIndex=All",
                                   @"Service=AWSECommerceService-Y",
                                   [NSString stringWithFormat:@"Timestamp=%@", [[DateHelper UTFStringFromDate:[NSDate date]] urlencode]]
                                   ].mutableCopy;

if (page != 0) {
    [array insertObject:[NSString stringWithFormat:@"ItemPage=%ld", page] atIndex:3];
}
       
[array addObject:[NSString stringWithFormat:@"Signature=%@", [self _getSignatureFromParams:array]]];

...

- (NSString*)_getSignatureFromParams:(NSArray*)params
{
    NSString* paramsString = [params componentsJoinedByString:@"&amp;"];
   
    NSString* string = [NSString stringWithFormat:@"GET\nwebservices.amazon.com\n/onca/xml\n%@", paramsString];
   
    NSData *keyData = // AWSSecretKey"
    NSData *paramData = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData* hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH ];
    CCHmac(kCCHmacAlgSHA256, keyData.bytes, keyData.length, paramData.bytes, paramData.length, hash.mutableBytes);
   
    return [[hash base64EncodedStringWithOptions:0] urlencode];

}

miércoles, 28 de septiembre de 2016

Swift: Add icon to label

let attachment: NSTextAttachment = NSTextAttachment()
        attachment.image = UIImage(named: "information icon")
        attachment.bounds = CGRect(x: 0, y: -5, width: attachment.image!.size.width, height: attachment.image!.size.height)
        
        let attachmentString: NSAttributedString = NSAttributedString(attachment: attachment)
        let attributedText: NSMutableAttributedString = NSMutableAttributedString()
        attributedText.append(attachmentString)
        attributedText.append(NSAttributedString(string: " We will never post anything to Facebook"))
        

        informationLabel.attributedText = attributedText

Swift: Tex with various colors or formats

        let differentColorText: String = "60 seconds"
        
        let fullText: NSString = "Match when you engage\nmore than 60 seconds in\na conversation."
        
        let range: NSRange = fullText.rangeOfString(differentColorText)
        
        let string: NSMutableAttributedString = NSMutableAttributedString(string: "Match when you engage\nmore than 60 seconds in\na conversation.")
        string.addAttribute(NSForegroundColorAttributeName, value: UIColor.lightGrayColor(), range: range)
        

        titleLabel.attributedText = string

martes, 13 de septiembre de 2016

iOS: UITableView add selected background and select row

Cell:

- (void)awakeFromNib
{
    UIView *selectionColor = [[UIView alloc] init];
    selectionColor.backgroundColor = [ColorHelper sickGreen];
    self.selectedBackgroundView = selectionColor;
}

ViewController containing table view:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
   // Set selected or not selected here. Doing it anywhere else has no result because prior to showing
   // the cell iOS sets selected to NO after that this method is called
}

jueves, 1 de septiembre de 2016

iOS: Change statusbar background color

- (void)_setStatusBarBackgroundColor:(UIColor *)color
{
    UIView *statusBar = [[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"] valueForKey:@"statusBar"];
    
    if ([statusBar respondsToSelector:@selector(setBackgroundColor:)])
    {
        statusBar.backgroundColor = color;
        
    }

}

jueves, 25 de agosto de 2016

iOS: View ignoring touches but the ones inside its subviews



The "Request product button" was inside "Container view" so I was either unable to click on it or unable to scroll the collection view below the "Container view"

Solution:

Subclass UIView and assign that subclass class to "Container view" and implement the following:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self) return nil;
    return hitView;

}

[super hitTest:point withEvent:event] will return the view touched that is the deepest in the view hierarchy.

miércoles, 17 de agosto de 2016

iOS: Change back button navigation bar

Objective C

1) Change back button color

self.navigationController.navigationBar.tintColor = [UIColor whiteColor]; // Change back button color

2) Remove back text








Swift

1) Change back button color

self.navigationController!.navigationBar.tintColor = UIColor.whiteColor()

2) Remove back text




Note: You can set the back button color in the IB by clicking on the Navigation Bar and settings its tint color

viernes, 5 de agosto de 2016

iOS: Custom property in interface builder

Objective C

@property (nonatomic, strong) IBInspectable UIImage* customImage;

- (void)awakeFromNib
{
    [super awakeFromNib];
    
    // Do something with customImage
}

Swift

@IBInspectable var customImage: UIImage

jueves, 21 de julio de 2016

iOS: Upload image with multipart AFKNetworking 3.0

Objective C

#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
    
    [self.pictureImageView setImage:image];
    
    [self showActivityIndicator];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),  ^{
    
        [[Server sharedInstance] uploadProfileImage:info user:self.user callback:^(ServerResponse *serverResponse) {
            
            [self hideActivityIndicator];
        }];
        
        
    });
}


- (void)uploadProfileImage:(NSDictionary*)imageInfo user:(User*)user callback:(void (^)(ServerResponse* serverResponse))callback
{
    UIImage *image = [imageInfo valueForKey:UIImagePickerControllerOriginalImage];
    NSURL *referenceURL = [imageInfo valueForKey:UIImagePickerControllerReferenceURL];
    
    NSString * ext = [self _extentionFromReferenceURL:[referenceURL absoluteString]];
    
    NSData* data = nil;
    
    if ([ext isEqualToString:@"jpeg"]) {
        data = UIImageJPEGRepresentation(image, 0);

    } else {
        data = UIImagePNGRepresentation(image);
    }
    
    AFJSONRequestSerializer* reqSerializer = [self _newSerializer];
    [reqSerializer setValue: [NSString stringWithFormat:@"JWT %@", [Preferences apiToken]] forHTTPHeaderField:@"Authorization"];
    [reqSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
    [self.netmanager setRequestSerializer:reqSerializer];
    
    [self.netmanager PATCH:[NSString stringWithFormat:@"user-profiles/%@/", user.profile.profileId] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        
        NSString* mimeType = [NSString stringWithFormat:@"image/%@", ext];
        
        [formData appendPartWithFileData:data
                                    name:@"profile_picture"
                                fileName:[NSString stringWithFormat:@"profile-picture.%@", ext] mimeType:mimeType];
        
        // etc.
    } progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        
        NSLog(@"Response object: %@", responseObject);
        
        [self _checkAndHandleErrorIfAny:responseObject noErrorCallback:^(id response) {
            callback([[ServerResponse alloc] initWithObject:nil]);
            
        } retryCallback:^{
            [self uploadProfileImage:imageInfo user:user callback:callback];
            
        } errorCallback:^(NSError *error) {
            callback([[ServerResponse alloc] initWithError:error]);
        }];
        
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"Error: %@", error);
        callback([[ServerResponse alloc] initWithError:error]);
    }];


}

Swift

// Using alamofire

func uploadProfilePicture(_ image : UIImage, completion:@escaping(_: Any?)->Void) {
        
        let imageData = UIImageJPEGRepresentation(image , 1)
        
        Alamofire.upload(multipartFormData: { (multipartFormData) in
            multipartFormData.append(imageData!, withName: <parameter_name>, fileName: "swift_file\(arc4random_uniform(100)).jpeg", mimeType: "image/jpeg")
            
            //            for key in parameters.keys{
            //                let name = String(key)
            //                if let val = parameters[name!] as? String{
            //                    multipartFormData.append(val.data(using: .utf8)!, withName: name!)
            //                }
            //            }
        }, to: "\(URLs.addProfilePicture)/0", method: .post, headers: getRequestHeaders()) { (result) in
            switch result {
            case .success(let upload, _, _):
                
                upload.uploadProgress(closure: { (Progress) in
                    print(Progress)
                })
                upload.response(completionHandler: { (response) in
                    print(response)
                })
                
            case .failure(let encodingError):
                completion(nil)
            }
        }

    }