緯創事件點出印度管理問題,鴻海等台廠如何克服挑戰?

 緯創位於印度的 Narasapura 廠上週發生暴動事件,震驚業界。事件發生後,緯創現已解僱印度高級業務主管,同時重組團隊,並設立 24 小時的電話供員工匿名投訴。此次事件,雖說因工資爭議而引起,卻同時點出台廠在印度製造所面臨的「種姓制度」管理難題。

種姓制度是超級管理難題

緯創位在印度卡納塔卡省的 Narasapura 廠發生暴動,起因主要是工資爭議,有部分工人沒有按時得到報酬或獲得適當酬勞;然而,階級分明的種姓管理制度,或許才是本次暴動的潛藏禍根。印度「種姓」社會制度階級分明,社會地位低落的工人容易與管理人產生矛盾。

根據香港經濟日報報導,台灣企業在各國經營時,為了融入當地環境維持長期經營,多會推動人事在地化的策略。但是,印度的種姓制度,往往使得台商在實踐本土化管理時,要更小心處理階級問題;避免高階級的主管與低階級的員工出現矛盾或衝突。

對此,供應鏈人士也透露,台灣主管向來較常採用「搏感情」方式,與工人一起用餐、一起同歡,主管與工人間的階級沒有那麼明顯,做法也比較平等。但隨著在地化成趨勢,台灣製造廠開始聘用在地主管;由於印度有種姓制度,所以印度高階主管上任後,往往會一改過去台灣主管的平等作法或人事、勞務安排。這或許是緯創本次發生暴動的主要因素之一,使原本在緯創工作或已與緯創簽訂合約的勞務公司受影響,種下不滿因素。

也因此當地警方同時也在調查,是否有人為了宣洩不滿,鼓動基層工人暴動砸廠;卡納塔卡省工業廳長也表示,這起暴力事件可能是緯創與勞務公司和工人之間溝通不良所致。

如何管理維持穩定,女性員工或成一大關鍵

然而,緯創印度廠發生暴動後,並未影響台灣電子製造業者前進印度的計畫。像是和碩表示,大趨勢不受影響,會按先前規劃,印度廠最快明年下半年量產。鴻海也稱清奈擴產進度不會受此事件影響,同時鴻海與集團旗下富智康持續向印度政府申請生產獎勵。

這些持續實施印度製造策略的業者,究竟該如何因應種姓制度,維持管理、營運穩定?或許,鴻海去年已先實施關鍵策略,就是以女性員工為主。

2015 年,鴻海集團旗下富士康首座印度廠在印度安德拉省斯里市(Sri City)啟用;富士康印度工廠聘用將近 1.5 萬名勞工,女性約占九成,為多家公司組裝手機。第二座印度手機廠 2017 年在泰米爾納德省的斯利柏倫菩德(Sriperumbudur)開張,距第一座廠約 2 小時車程;這座廠聘用 1.2 萬人,廠房作業局部自動化。

在印度主管 Josh Foulger 領導下,印度富士康已成為重要的製造基地,未來也持續有擴廠計畫。那麼,為何會選擇以女性員工為主?Foulger 表示,事實上,他打從一開始就決定聘用女性勞工,因為執教鞭的母親說服他給婦女機會。

Foulger 透露,在印度,工廠女工不像中國那麼常見,鄉村婦女往往無酬做家事或進行農務;原本安德拉省斯里市甚至禁止女性輪值工廠夜班,直到當地政府和法院介入才改變;同時,也由於印度製造商大多偏好僱用男性,所以很輕鬆就達到招聘目標。

Foulger 強調,儘管必須增加保全、接駁巴士、宿舍等開銷,但這一切很值得,因為女性員工對獲得工作機會十分知足感恩,所以工作都十分賣力;同時多數印度女性工作時,心中都會有具體目標,像是償還家裡債務、讓小孩上更好學校等。

雖然此作法不能說是克服種姓制度的唯一解方,但鴻海印度廠以女性員工為主的特色,確實在營運管理保持一定穩定,並有利於未來擴產計畫;或許緯創事件發生後,此策略能供日後前進印度製造的台廠參考。


Progressive Web App 會是未來趨勢嗎?

https://blog.techbridge.cc/2016/07/23/progressive-web-app/


何謂 Progressive Web App (PWA)

先講結論,Progressive Web App 是希望能夠讓 Web application 盡可能的在各種環境(網路環境、手機作業系統等)下都能順暢且不減功能性的運作,並讓你的 Web App 可以:

  1. 直接被使用者安裝到桌面
  2. offline 使用
  3. 擁有推播功能
  4. 開啟時看不到 URL Bar(類 Native app 的使用經驗)
  5. 開啟時有 Splash Screen

而要做到這些事情,整個 PWA 的設計要點就會包含以下特性:

  • Progressive - 漸進增強:在越完善的環境下,能執行更加完整的服務,若環境不許可,能夠優雅降級,運行最基本的功能。

  • Responsive - 響應式介面:能夠在各種螢幕尺寸下顯示、能夠因應多種輸入方式與設備回饋(震動、音頻等)。

  • App-like - 類原生程式的操作模式與使用者介面:採用原生平台(Native App)的 Style 與資料更新方式(利用 service worker 存取快取資源)。

  • Fresh - 持續更新:使用 Service worker API 來自動更新應用程式(無需透過 App store, Google Play 等)。

  • Safe - 應全面採用 HTTPS 提供最基本的安全防護。

  • Discoverable - 透過設置 manifest 檔案,一樣能進行 SEO 優化,讓搜尋引擎找得到你的 APP。

  • Re-engageable - 透過推播,能主動與使用者互動。

  • Installable - 可安裝:透過 Add To Home 等方式,將 Web App 放在手機桌面,並且能在應用程式中單獨列出與切換,就像一般的 App 一樣,但完全不用透過應用程式商店下載。

  • Linkable - 透過 URL 可以隨時分享你的 App。

上面是官網所列出的,而紅色是我認為較為重點的特徵,而在這些重點特徵下,最大要點就是 Service worker。有了 Service worker 的幫助,你可以實作出離線可用的 Web App,讓 User 操作起來有更佳的使用體驗。

iOS 中 UITableView 和 自定義 UITableViewCell 的使用方法

使用纯代码自定义UItableviewcell实现一个简单的微博界面布局:https://www.cnblogs.com/wendingding/p/3761730.html


https://www.youtube.com/watch?v=2rd0FKN9XH8&list=PLzKtnppOmiXAYGqXEU_owKS-TH6FEZYeE&index=79


https://www.jianshu.com/p/f30eab24401f  頁庫存檔:

本文的重点并不仅是UITableView的基本使用方法,而是强调有关UITableView和UITableViewCell开发过程中的一些具体细节问题。基本信息请参阅Apple开发文档《Table View Programming Guide for iOS》


概述

Table可能是最擅长于展示数据的一种UI部件。因此UITableView这个类是iOS App开发中除button和Label之外最常用的控件类型。几乎任何一个App都离不开tableView。使用UITableView很简单,核心就是要实现两个protocol。这是由于tableView在MVC中只是V这一环,所以它需要额外的支持提供另外的MC两个环节的功能才能让一个table完整的工作。而这种支持实现的途径就是protocol,Apple要求开发者提供实现** UITableViewDataSource** 和UITableViewDelegate 这两个protocol的支持类来协同对应的UITableView的工作。一般情况下,实现delegate protocol的类是UITableViewController,而data source protocol 可以是controller负责,也可以是其他helper类完成。但更多情况下,我更倾向于单独的modal wrapper类来完成。现在很多的建议data source尽可能不要放在controller中,这样有利于解决mass controller的问题。可以参考objc.io这篇文章:《Lighter View Controllers》


鉴于UITableView是如此的重要,iOS替我们定制化了两种类型的tableView:static和dynamic。前者适用于表格内容相对固定的场景,更多的使用在诸如Setting panel,Detail panel的地方;而后者适用于表格内容不固定,行数动态变化的场景,更多的使用在网络请求返回后,将动态的数据进行内容展示等。虽然Apple内置了几种(确切的说到目前为止是4种)table的style,但是对于App开发而言,大多数情况下都需要自行定制table对数据的展示方式,因此相对应的,table cell的定制化成为App开发的必修课题。


那么下文将介绍一下Static table的使用中需要注意的一些地方和dynamic table中cell开发的方法总结。


关于Static Table的报错

static table的设置方法很简单,在Xcode中设置UITableView的类型为static即可。

这里着重强调一个问题,绝大多数使用static table view的人都会遇到xcode报出的一个莫名其妙的错误:

error.png

而这个问题的原因是:放置static table的View Controller <u> ** 必须为iOS内置的UITableViewController类型 ** </u>

据说这是xcode的一个bug,但是到目前为止还没有被“修复”的迹象,总而言之,造成的结果就是,如果你想在某个页面放置一个static table view,你必须单独放在UITableViewController中,而且仅仅手动将自己的viewController的类继承自UITableViewController或者在xib中强制改成UITableViewController都不行,必须是原生的UITableViewController。可是很多情况下我们确实需要在自己的viewcontroller中添加一个static table view。怎么办?解决方法是使用Container View。


在你自己的ViewController中拖入一个Container View

删除这个Container View自动创建的segue和对应的target view controller

containerView.png

拖入一个新的UITableViewController,加入一个table view,修改类型为static;

Ctrl-drag container view到这个UITableViewController,在弹出的segue类型中选择Embed:

statictable.gif

当然,这种方式只适用于storyboard操作并且要求支持Container VC的iOS版本。在其他情况下,可以直接使用addSubView:,将UITableViewController的view(当然就是tableView)加到自己的“container”view之下。


UITableViewCell的使用方法

下文的重点是总结UITableView和UITableViewCell的核心方法。更多详情可以参考Apple的官方文档。


1. 预定义Cell

iOS自定义了4种常见的Cell格式,在UITableViewCell.h中的注释中Apple给了一些明确的提示这些预置的style一般都适用于什么场景:

typedef enum {
  UITableViewCellStyleDefault,  // Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x)
  UITableViewCellStyleValue1,  // Left aligned label on left and right aligned label on right with blue text (Used in Settings)
  UITableViewCellStyleValue2,  // Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts)
  UITableViewCellStyleSubtitle  // Left aligned label on top and left aligned label on bottom with gray text (Used in iPod).
} UITableViewCellStyle

4种类型在Xcode中对应的选项为:Basic, Right Detail, Left Detail和Subtitle。在iOS8下测试,对应的示例图如下:

Basic:

Basic.png

Right Detail有图时:

rightdetail1.png

Right Detail无图时:

rightdetail2.png

Left Detail:

leftdetail.png

Subtitle:

subtitle.png

在这4种格式都统一有3个property可以供你使用:

textLabel:一个主标题

detailTextLabel:一个副标题

imageView:一张详情缩略图片

实际上这些预置类型就是把这3种元素做了些取舍然后在不同的位置组合了一下。我觉得在设计App的时候,在任何情况下,设计师和工程师都应当首先考虑这些预置的类型能不能满足需求,除非有足够的必要,否则不要轻易的浪费经历在重复构造定制化的View上。个人觉得Subtile模式已经适用于绝大多数对UI要求不高的场合。你完全可以自己修改这3个控件的一些属性来对UI进行微调。比如你可以尝试将imageView的大小放大一些。


2. 自定义Cell

UITableView是通过调用UITableViewDataSource中的tableView:cellForRowAtIndexPath:方法来获取每一行所需要的Cell的,所以绝大多自定义Cell的处理过程都是在这一步完成,另外由于UITableViewCell本身也是一个UIView,所以你也可以在UITableViewDelegate中的tableView:willDisplayCell:forRowAtIndexPath: 方法中对Cell的view做最后的定制化。


注意: Apple明确指出,在tableView:willDisplayCell:forRowAtIndexPath:中应当只修改“state-based properties”,比如selection和background color等等,但是不应该是内容(content),也就是不要在这里进行任何数据处理。


2.1 自定义Cell的创建

有以下几种方法:

方法1:使用Code继承预定义的cell样式,然后再手动添加自己的view

这是Apple官方文档中的示例,它通过调用initWithStyle:reuseIdentifier:使用UITableViewCellStyleDefault参数来创建一个Cell,为了方便期间,我对代码稍做了些改动,一个是简化了数据加载,另一个是用NSTextAlignment替换了废弃的UITextAlignment:

  #define MAINLABEL_TAG 1
  #define SECONDLABEL_TAG 2
  #define PHOTO_TAG 3
  
  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @"ImageOnRightCell";
        static int i = 0;
        UILabel *mainLabel, *secondLabel;
        UIImageView *photo;

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

        if (cell == nil) {
              cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
              cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;

              mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)];
              mainLabel.tag = MAINLABEL_TAG;
              mainLabel.font = [UIFont systemFontOfSize:14.0];
              mainLabel.textAlignment = NSTextAlignmentRight;
              mainLabel.textColor = [UIColor blackColor];
              mainLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
              [cell.contentView addSubview:mainLabel];
  
              secondLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 20.0, 220.0, 25.0)];
              secondLabel.tag = SECONDLABEL_TAG;
              secondLabel.font = [UIFont systemFontOfSize:12.0];
              secondLabel.textAlignment = NSTextAlignmentRight;
              secondLabel.textColor = [UIColor darkGrayColor];

              secondLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
              [cell.contentView addSubview:secondLabel];
  
              photo = [[UIImageView alloc] initWithFrame:CGRectMake(225.0, 0.0, 80.0, 45.0)];
              photo.tag = PHOTO_TAG;
              photo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
              [cell.contentView addSubview:photo];
        } else {
              mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
              secondLabel = (UILabel *)[cell.contentView viewWithTag:SECONDLABEL_TAG];
              photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
        }

        mainLabel.text = [NSString stringWithFormat:@"Title_%d", i];
        secondLabel.text = [NSString stringWithFormat:@"Description_%d", i];
        i++;
        NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
        photo.image = theImage;

        return cell;
  }

最终效果如下:

CustomCell1.png

这里有两个重点:

Cell的重用机制

重用机制对于UITableView而言是非常重要的概念,这能够显著提高滑动TableView时的性能。如果不使用重用,那么每次新的Cell出现在屏幕上时都需要新创建一个,这对快速滑动而言是非常影响用户体验,并且会占用系统大量的内存开销。iOS的TableView使用的重用机制在原理上很简单,就是系统自动维护一个queue,这个队列放着一定数量的准备好的Cell UI object,滑出屏幕范围之外一定“距离”的Cell都会被回收到这个queue里,给马上要滑入屏幕范围内的Cell复用。

使用重用的方法核心是两个概念:Cell Identity和dequeue。前者是标识一种具体的Cell的id,后者是将Cell从复用队列中取出的实际操作。首先你需要用这个id告诉系统你将要用于重用的Cell是谁(注册),然后你使用这个id从重用的队列里取出来(复用)。具体到本例中的API就是如下两个:initWithStyle:reuseIdentifier:和dequeueReusableCellWithIdentifier:。后面将看到,对于不同情况下创建的Cell,注册和复用的调用也并不相同。

必须把自定义的控件添加在cell的contentView上,而不是view上,也就是:

 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
 ...
 // Correct!
 [cell.contentView addSubview:yourCustomComponetView];
 // Wrong!
 // [cell.view addSubview:yourCustomComponentView];

再次强调一点,Cell的Content View不是自己的root view。关于Cell View的结构可以参考这篇文章:《制作一个可以滑动操作的 Table View Cell》

这里只摘出最终结论,能够让你对一个Cell的view有直观的理解。

对于一个如图所示的Table而言:

sample.png


它的TableViewCell的View层级结构是:

<UITableViewCell; frame = (0 396; 320 44);> //1
   | <UITableViewCellScrollView; frame = (0 0; 320 44); > //2
   |    | <UIButton; frame = (302 16; 8 12.5)> //3
   |    |    | <UIImageView; frame = (0 0; 8 12.5);> //4
   |    | <UITableViewCellContentView; frame = (0 0; 287 44);> //5
   |    |    | <UILabel; frame = (15 0; 270 43);> //6

这个Cell 里有六个视图:

* UITableViewCell 这是最高层的视图。 Frame 显示它有 320 点宽和 44 点高——宽度和高度都和预期的一致,因为它和屏幕一样宽,而高度就是 44 点。

* UITableViewCellScrollView 虽然你不能直接使用这个私有类,但它的名字很好地暗示了它的功能。它的 Size 和 Cell 的一样。

* UIButton 它在 Cell 的最右边,就是 Disclosure Indicator 按钮。

* UIImageView 是上面 UIButton 的子视图,装载着 Disclosure Indicator 的图像。

* UITableViewCellContentView 另外一个私有类,它包含 Cell 的内容。这个类对于开发者来说就是 UITableViewCell 的 contentView 属性。但它只作为一个 UIView 来暴露在外,这就意味着你只在其上调用使用公开的 UIView 方法;而不能使用任何与这个类关联的任何私有方法。

* UILabel 显示 “Item #” 文本。


很显然,这里cell.contentView并不是cell.view。


方法2:使用xib绘制Custom Cell View

这是自定义Cell最常见也是最省力的方法:


首先在xcode中创建custom xib,拖拽需要的控件到xib上,并做好布局和限制;

2)新建自己的custom class,定义对应的outlet properties;

3)将xib的class设置成对应的custom class,然后将outlet和控件连接起来;

4)在适当的位置(一般为初始化的地方)调用registerNib:forCellReuseIdentifier:注册Cell;

5)在tableView:cellForRowAtIndexPath:中调用dequeueReusableCellWithIdentifier:forIndexPath:复用cell

下面的这个示例演示了上述步骤。在这个示例中,首先创建Custom Cell和xib的界面,其中有一张大图,下面有两个独立的label,然后我使用了tableView:willDisplayCell:forRowAtIndexPath:对每一行Cell的背景颜色做出最终设置,而在tableView cellForRowAtIndexPath:中对Cell的内容进行填充:


Custom View:

@interface MyTableCellView : UITableViewCell
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UILabel *name;
@property (weak, nonatomic) IBOutlet UILabel *date;
@end


Custom Xib:

CustomXib.png

在table View Controller中:

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup here ...

...

// register the cell to tell the system preparing to reuse it.

[self.tableView registerNib:[UINib nibWithNibName:@"TableCellView" bundle:nil] forCellReuseIdentifier:cellId];

}

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        // always reuse the cell
        MyTableCellView *cell = [tableView dequeueReusableCellWithIdentifier:cellId forIndexPath:indexPath];
        
        cell.frame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 250);
        NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
        cell.imageView.image = [UIImage imageWithContentsOfFile:path];
        NSDate *object = self.objects[indexPath.row];
        cell.date.text = [object description];
        return cell;
    }

    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"indexpath = %ld", indexPath.row);
        if ( indexPath.row % 2 == 0) {
          cell.backgroundColor = [UIColor redColor];
        }
        else {
          cell.backgroundColor = [UIColor greenColor];
        }
    }

Demo:

CustomCell2.png

方法3:使用code定义一个Custom Cell Class

这个在本质上和上一种使用xib的方法是一样的,只不过一个是用代码完全定制,一个是借助xib操作。但是在Cell重用的方式上有一定区别。上一种方法中,需要调用registerNib:forCellReuseIdentifier:来注册重用的Cell,在这里就需要用registerClass:forCellReuseIdentifier:方法来注册。与之对应的,获取重用的Cell的时候,调用dequeueReusableCellWithIdentifier:forIndexPath:方法。

Class myClass = [MyTableCellView class]; 
[self.tableView registerClass: myClass forCellReuseIdentifier:@"CustomCell"];
...
...
MyTableCellView *cell = [self.tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:path];
cell.label.text = @"text";
...

注意 dequeueReusableCellWithIdentifier:和dequeueReusableCellWithIdentifier:forIndexPath:的区别!!


如果你注册过Cell,在没有可用的cell时,前者会返回nil;而后者永远都会从注册的nib或者class中替你创建一个可用的Cell。也就是说,前者调用你需要手动检查nil,而后者不需要;

如果你从没有注册过cell,在没有可用的cell时,前者会返回nil,后者……直接崩溃!也就是说,调用后者你 必须确保注册过cell 。

2.2 访问Cell中的控件:

xib中使用outlet

这个应该不用多说,在Cell的原型中(不管是Static cell还是Dynamic cell)定义outlet properties,然后在xib中拖拽连接对应的控件即可;Apple官方文档上的示意图:


connect_outlet.jpg


connect_static_objects.jpg

代码中使用viewWithTag:

这个是获取parent view上某个特定view的快捷方法,首先需要设置一个sub view的tag,然后使用viewWithTag:来访问这个sub view。设置时可以通过xcode在xib中设置tag标签,也可以直接通过tag property手动设置:

创建时:

mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)];
mainLabel.tag = MAINLABEL_TAG;
// customize the label here...
[cell.contentView addSubview:mainLabel];

访问时:

 mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];

有关Table和Cell的性能需要注意的问题

关于这个话题,Apple并没有用过多的篇幅介绍,但是在官方开发文档中明确提出了3点意见:


注意重用(Reuse Cell)

这点我们已经在上文中着重强调过了。


避免反复的调整Cell的布局(Avoid relayout of content)

只在创建每一个Cell的时候布局一次,而不要每一次获取Cell的时候都去重新布局。


避免透明的subviews (Use opaque subviews)

自定义cell的时候,尽可能避免使用透明的控件,因为透明控件在table滑动时将增大渲染开销。


总结

本文主要从Static table和Dynamic table两方面总结了UITableView和UITableViewCell的核心使用方法和问题,并着重介绍了Custom Cell的几种方法和注意事项。


另外,有兴趣的话,UITableView还有另外几个比较关键的功能可以继续研究,一个是Editing mode,一个是Table Index,还有一个相对也很重要的功能自定义Header和Footer View。有空的话可以再总结一下。希望此篇能帮助到您。


2016年4月5日,完稿于南京。


團隊如果有一兩個人能力僅勉強勝任的話,會拉低團隊所有人的表現

 1.Netflix 創辦人海斯汀透過一場「關鍵裁員」,透析組織氣氛經營與人才篩選提高人才密度,對於Netflix的關鍵影響。

2.懶鬼、討厭鬼、憂鬱消極鬼,當團隊中出現這三種人,不論再優秀的團隊,其他成員也會被單一特定人士的行為影響,因而嚴重拖累團隊表現。


2001年春天,危機來襲。第一波網路泡沫破滅,無數網路公司倒閉消失。所有創投基金都中止了。我們一夕之間籌不到公司運作需要的周轉資金,而我們的公司又遠稱不上賺錢。公司士氣低迷,而且即將再往下挫,因為我們必須解雇1/3的員工。

我找馬克和派蒂.麥考德(Patty McCord)坐下來商量——派蒂是從Pure Software跟著我過來的同事,當時擔任人資長。我們仔細審核每一名員工的貢獻。沒有誰表現明顯特別差。所以我們把員工分成兩堆:80名表現最佳的員工,我們會留下;40名相較沒那麼出色的員工,我們會請他走。那些獨具創意、工作成績亮眼,而且與他人合作融洽的人,自然立刻分進「留下」那組。難是難在有很多介於及格邊緣的案例。有些人做同事做朋友都是好人,但工作表現平平。也有些人是工作狂,但判斷力不穩定,時常需要手把手地教。少數有幾個特別有才華,工作能力也強,但是愛抱怨或悲觀消極。這些人多半都得離開。可以想見,這個過程一點也不輕鬆。

我太太總說,宣布裁員前那幾天,我簡直如坐針氈。她說得沒錯,我擔心辦公室的士氣會盪到谷底。我深信在我打發了他們的朋友和同事以後,留下的人也會覺得公司待員工沒有誠信,所有人到時絕對都會很不滿。更何況「倖存者」還必須扛下離開的人的工作,可想而知一定會有很多抱怨。我們已經資金短缺,還承受得了士氣再瓦解嗎?

裁員的那一天到了,場面一如預期的難堪。被裁的人有的哭了,有的摔門,也有人氣得大吼大叫,到中午才告一段落。我則默默等待風暴進入下半場,也就是留下員工的反彈⋯⋯沒想到,除了幾許眼淚和明顯可見的悲傷之外,所有人都很平靜。接下來幾星期,氣氛大幅好轉,我一開始還不知道為什麼。我們依舊處於共體時艱的狀態,而且才剛裁了1/3員工,但辦公室卻突然活絡起來,迸發熱情、活力和創意。


幾個月後進入耶誕節假期,DVD播放機是那年熱銷的禮物。到了2002年初,我們的郵租DVD生意再度飛速成長。轉眼之間,我們的工作量翻升好幾倍——儘管員工數比之前少了1/3。令我驚奇的是,同樣是這80個人,他們處理所有工作的熱情似乎更勝以往。他們的工作時間拉長了,鬥志卻極高。不只是我們的員工變快樂,我早上醒來也等不及想去上班。那段日子,我每天順路載派蒂去公司,她也住聖克魯斯,每當我轉進她家門前,她幾乎都是雀躍地跳上車,臉上掛著大大的笑容說:「里德,這到底是怎麼回事?這就是戀愛的感覺嗎?難不成是某種化學作用,這種興奮感之後就會消退?」


派蒂講到了重點。整個辦公室感覺就像充滿了瘋狂愛上工作的人。


我不是在提倡裁員,而且也慶幸Netflix自此以後不必再做相同的事。但在2001年裁員風波之後那幾天,乃至於那幾個月,我發現了幾件事,徹底改變我對員工動力和領導責任的理解。我突然有所領悟,我對人才密度在組織中發揮的作用認知從此不同。我們從中學到的經驗,成為後來指引Netflix走向成功的基礎之一。


2001年裁員事件後,派蒂和我花了數十趟通勤車程討論這件事,想知道公司的工作氛圍怎會突然急轉彎向上,我們又該怎麼做,才能維持這股正向的動能。我們漸漸明白,我們的「人才密度」急遽提升,正是公司進步的推手。


優秀的人會幫助彼此進步更快

每位員工都具備某些才能。過去我們有120人的時候,有些員工才能出眾,另一些能力平平。總體來說,我們有相當的才能分散在全體人力之中。裁員以後,因為只留下最有能力的80個人,我們的才能總量減少了,平均每名員工的才能值卻提高了。因此,我們的才能「密度」提升了。


我們發現,人才格外密集的公司,也是人人都想效力的公司。高績效表現的員工在整體人才密度高的環境裡,尤其如魚得水。


我們的員工從彼此身上能學到更多,團隊的績效也更高。這又提升了個人的動力與滿足感,進而帶領公司整體實現更多成就。我們發現讓周圍環繞菁英,能讓原本已經不錯的成果彈射到全新境界。


最重要的是,與真正有才能的同事一起工作令人興奮、帶來鼓舞,而且充滿樂趣——相較過去只有80名員工,今日公司已有7000名員工也一樣。


我經由事後觀察發現,團隊如果有一兩個人能力僅勉強勝任的話,會拉低團隊所有人的表現。如果你的團隊有5名優秀下屬,另兩個差強人意,那這兩個勉強勝任的員工會:


耗盡主管心力,主管照顧優秀員工的時間減少。

降低團體討論品質,拉低團隊的總體智商。

迫使其他人必須養成另一套方法與他們共事,損害效率。

劣幣驅逐良幣,迫使追求卓越的人離職。

形同告訴團隊你能接受庸才,使問題更加複雜。

對優秀菁英來說,好的工作環境不在於辦公室裝潢鋪張、有漂亮健身房,或午餐有壽司吃到飽。身旁環繞有能力又懂得合作的人才,這些人又能幫助你變得更好,這種喜悅才是重點。當每個成員都很優秀,工作表現就會出現正向循環,員工能彼此學習、激發彼此的動力。


表現會傳染

你手下有平庸的人,會讓許多原本優秀的下屬也表現平庸。但若你的團隊全部由表現優異者組成,每個人都會激勵彼此做到更好。


澳洲新南威爾斯大學教授威爾.菲普斯(Will Felps)做過一項研究,結果令人驚奇,突顯了職場環境中行為的傳染力。他將大學生每4人一組,分成多組,請每組在45分鐘內完成一項經營管理任務。成效最好的一組可以獲得100美元獎金。

學生不知道,有些組內其實混入了演員,分別扮演以下幾種角色:「懶鬼」不參與討論,會把腳翹到桌上,傳簡訊和人聊天;「討厭鬼」會嘲諷挖苦,說些「你太扯了吧?」和「看來你根本沒上過商學課」之類的話;還有「憂鬱消極鬼」,臉上一副他家貓咪剛死掉的表情,抱怨任務做不到,質疑團隊不可能成功,有時還會乾脆趴在桌上。演員不會向其他組員透漏身分,其他人以為他們是一般學生。


菲普斯教授首先發現,即使小組中其他組員特別聰明又有能力,但一個人的不良行為仍會拉低全組的效率。這一個多月的時間,他進行了數十次試驗,組內有不良成員的組別,表現比其他組整整差了3成到4成。


這些發現顛覆了幾十年的研究,過去的研究多認為,團體內的個人會屈從團體的價值觀和行為準則。但事實卻是,某一個人的行為會快速感染團體其他成員,即使團隊才相處45分鐘。


菲普斯教授解釋:「令人驚訝且不解的是,團隊中的其他人為什麼會開始出現那個人的特質。」假冒者是懶鬼的時候,組內其他人也會對企劃失去興趣,最後總會有人跳出來宣稱任務其實也沒那麼重要。演員扮演討厭鬼,組內其他人也會開始互相羞辱,話中帶刺。演員如果是憂鬱消極鬼,影響最明顯。菲普斯說:我還記得我看到其中一組的影片。一開始所有組員都坐得直挺挺的,活力充沛,等不及想挑戰這個可能有難度的任務。但是到後來,每個人姿勢都垮了,頭都趴在桌上。」


菲普斯教授用實例說明了我和派蒂在2001年學到的事。團隊裡即使只有少數表現平庸的人,他們的表現仍有可能傳染給其他人,拉低整個組織的表現。


我們大多數人應該都能想起人生中有過的類似時刻,親眼目睹這種行為感染法則上演,我12歲時就見過一次。


我1960年出生在麻州。小時候的我很平凡,沒什麼特殊才華或出眾能力。小學3年級時,我們全家搬到華盛頓特區,生活過得還不錯,我也有一大群朋友。但到了6、7年級的時候,學校有一個叫凱文的同學,會聚集大家打架。他也沒有特別針對或霸凌我們之中的誰。他多數時候並不起眼,卻創造出一種行為模式,連帶影響了我們其他人的行為表現和相處方式。我很不想加入,但不參與打架感覺會比湊一腳還要丟臉。而且誰打輸、誰打贏,真的會決定大家一整天的氛圍。要是沒有凱文,我們彼此互動和一起玩的方式一定會大有不同。因此當我爸告訴我們要搬回麻州的時候,我簡直等不及立刻就走。


2001年裁員後,我們才發覺原本在Netflix裡,也有一小群人成就了令人不愉快的工作氣氛。從數不清的小地方看得出很多人不適任他們的工作,看在其他人眼裡則暗示公司可以接受平庸的表現,長久下來,就拉低了每個人的表現。


2002年,我們對於優良的職場需要具備的條件有了更多認識,我和派蒂立下承諾,我們往後的首要目標,就是要盡一切所能維持裁員後的人才密度,以及隨之而來的所有優點。今後我們會雇用最優秀的員工,支付業界最高的薪水。我們會訓練主管拿出勇氣和紀律,凡有不適任的行為或表現未達模範標準的員工一律裁除。我開始嚴格檢視,從接待櫃檯到最高執行團隊,確保Netflix的員工都是業界表現最佳、合作能力最強的人才。



iOS 開發:去除頭尾空白、去除特殊符號

 NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"/@/:;()¥「」/"、[]{}#%-*+=_\\|~<>$€^•’@#$%^&*()_+’\""];

NSString *trimmedString = [city.text stringByTrimmingCharactersInSet:set];

 

 

NSString *str = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

    

 

NSUInteger len = 0;

len = [trimmedString length];

iOS 開發:字符串去掉特殊字符(只保留大小寫英文字母和數字)

https://www.jianshu.com/p/082d3739f5db

調用 removeSpecialCharacters 方法


- (NSString *)removeSpecialCharacters:(NSString *)value{
    NSMutableString *string = [NSMutableString stringWithString:value];
    unichar c;
    for(int i=0;i<string.length;i++){
        c = [string characterAtIndex:i];
        if(![self charIsNum:c]){
            //First determine if it is a number. If it is not a number, continue to determine whether it is a letter.
            if(![self charIsZimu:c]){
                //If it is not a letter, it means neither a number nor a letter
                NSString *str = [NSString stringWithCharacters:&c length:1];
                NSLog(@" removeSpecialCharacters str=%@",str);
                NSRange range = NSMakeRange(i, 1);
                [string deleteCharactersInRange:range];
                --i;
            }
        }
    }

    NSString *newstr = [NSString stringWithString:string];
    NSLog(@" removeSpecialCharacters after str=%@",newstr);
    return newstr;
}

//Judging whether it is a number
-(BOOL)charIsNum:(unichar)chars{
    if(isdigit(chars)){
        return YES;
    }
    else {
        return NO;
    }
}

//Determine if it is a letter
-(BOOL)charIsZimu:(unichar)chars{
      if((chars<'A'||chars>'Z')&&(chars<'a'||chars>'z'))
      {
            return  NO;
      }
      else {
            return YES;
      }
}


- (NSString *)removeSpecialCharacters:(NSString *)value{

    NSMutableString *string = [NSMutableString stringWithString:value];
    unichar c;
    for(int i=0;i<string.length;i++){
        c = [string characterAtIndex:i];
        if(![self charIsNum:c]){
            //First determine if it is a number. If it is not a number, continue to determine whether it is a letter.
            if(![self charIsZimu:c]){
                //If it is not a letter, it means neither a number nor a letter
                NSString *str = [NSString stringWithCharacters:&c length:1];
                NSLog(@" removeSpecialCharacters str=%@",str);
                NSRange range = NSMakeRange(i, 1);
                [string deleteCharactersInRange:range];
                --i;
            }
        }
    }

    NSString *newstr = [NSString stringWithString:string];
    NSLog(@" removeSpecialCharacters after str=%@",newstr);
    return newstr;
}

//Judging whether it is a number
-(BOOL)charIsNum:(unichar)chars{
    if(isdigit(chars)){
        return YES;
    }
    else {
        return NO;
    }
}

//Determine if it is a letter
-(BOOL)charIsZimu:(unichar)chars{
      if((chars<'A'||chars>'Z')&&(chars<'a'||chars>'z'))
      {
            return  NO;
      }
      else {
            return YES;
      }
}




程式語言編年史

程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...